SSM day01

简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

  • MyBatis前身是iBatis,本是Apache的一个开源的项目

  • ORM框架

    • 实体类和SQL语句之间建立映射关系
  • 特点:

    • 基于SQL语法,简单易学
    • 能了解底层封装过程
    • SQL语句封装在配置文件中,便于统一管理与维护,降低程序的耦合度
    • 方便程序代码调试

ORM框架

什么是ORM?

对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中

半自动ORM框架和全自动ORM框架?

全自动 ORM 映射框架可以通过对关联对象或者关联集合对象的操作进而操作数据库,而半自动框架在查询关联对象或
关联集合对象时,需要手动编写 sql 来完成

Hibernate与Mybatis有啥区别?

Hibernate 属于全自动 ORM 框架,Mybatis属于半自动ORM框架,半自动相较全自动最主要的还是在灵活性(sql语句优化),而全自动主要还是体现在效率(代码少写)

市面上常见的ORM框架

实际上市面上常用的几个语言都有自己的ORM框架(常用语言排行版网站:https://www.tiobe.com/tiobe-index/)

Java hibernate、mybatis、SpringData JPA
C# EF(Entity Framework)
Node.js TypeORM
GO GORM、XORM

未来发展趋势

目前在java行业中,hibernate、mybatis属于老牌的ORM框架,由此两大巨头牵引出另外两大老牌框架,分别是SSH以及SSM,java行内巨头Spring觉得SSM配置过于麻烦,推出Spring Boot,又因为微服务前后端分离概念的流行,推出了Spring Cloud全家桶的解决方案,且觉得mybatis还是过于繁琐,搞了一个Spring Data JPA(有可能也是未来大趋势),这个类似hibernate的全自动ORM,但又非常的智能且强大(用的都是同一套JPA标准)

基础环境准备

pom文件依赖声明

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

mybatis-config.xml

mybatis的基础配置文件,名字可自取,此处取名为mybatis-config.xml

文件头部

对应的头文件可以从官网帮助文档获取

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

常用标签

在解释几种连接方式之前,先简单地介绍下几个标签以及其作用

environments 标签

多环境标签,内部可包含多个environment标签,每个environment标签中包含多个属性

default标签表示应用的是哪个环境,常见的有dev、test、pro等

transactionManager标签

事务管理标签,其中type属性填写的是事务管理方式,此处使用JDBC模式

注意

  • 使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
  • 使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理

dataSource标签

数据源标签,type表示的是数据源的配置方式,POOLED表示池的模式,后期会对接第三方的数据源

property标签

属性标签,常规配置数据库连接的4个参数:driver、url、username、password,其中name和value分别代表变量名和值

数据连接文件配置的几种方式

方式1:直接写在datasource中(不推荐)

需要注意的是,此处如果直接写&符号而不是&amps; 会出现如下错误

实体 “characterEncoding” 的引用必须以 ‘;’ 分隔符结尾
<configuration>
    <environments default="dev">
        <!--对应各类的开发 测试 生产环境: dev test pro-->
        <environment id="dev">
            <transactionManager type="JDBC" />
            <!--数据源配置,后期会用第三方,如之前使用的德鲁伊-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
方式2:额外配置properties标签(了解)

在datasource中则采用${driver}的方式,其中{}中的变量名要与上述properties标签中的name一致

<configuration>
   <!-- <properties resource="database.properties"></properties>-->
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>
    <environments default="dev">
        <!--对应各类的开发 测试 生产环境: dev test pro-->
        <environment id="dev">
            <transactionManager type="JDBC" />
            <!--数据源配置,后期会用第三方,如之前使用的德鲁伊-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
方式3:外部添加properties文件,再通过properties标签中的 resource标签进行获取
<configuration>
   <properties resource="database.properties" />
   <environments default="dev">
       <!--对应各类的开发 测试 生产环境: dev test pro-->
       <environment id="dev">
           <transactionManager type="JDBC" />
           <!--数据源配置,后期会用第三方,如之前使用的德鲁伊-->
           <dataSource type="POOLED">
               <property name="driver" value="${driver}"/>
               <property name="url" value="${url}"/>
               <property name="username" value="${username}"/>
               <property name="password" value="${password}"/>
           </dataSource>
       </environment>
   </environments>
</configuration>

外部properties文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8
username=root
password=root
优先级关系

方式一内部编写的方式优先级高于方式二和方式三

如果方式2和方式3同时存在,形如

<properties resource="database.properties">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
</properties>

此时resource资源优先级最高

mapper.xml配置

新建xml文件

在resources资源文件夹目录下,添加mapper文件夹,在其中新建mapper.xml文件

XXXMapper.xml文件,一般XXX与实体类同名,后续新建的Mapper接口建议也与其同名,比如

**SmbmsUserMapper.java **

SmbmsUserMapper.xml

文件头部

与mybatis的配置文件相似,mapper.xml文件的头也可以在mybatis官方文档–入门中进行复制

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

非mapper动态代理(不推荐)

这种写法采用的是mybatis早期版本的写法,只需要mapper.xml以及mybatis-config.xml文件即可完成,但目前基本使用mapper接口来动态代理,因为采用这种方式过于麻烦

mapper.xml文件

注意此处以SmbmsUserMapper.xml为例,其中namespace和id的写法,具体可以看注释内容

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--在非动态代理模式下,namespace的值可以随意填写,只要保证唯一即可-->
<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <!--此处的id只要保证该mapper文件中,唯一id即可-->
    <select id="countUser" resultType="java.lang.Integer">
        select count(*) from smbms_user
    </select>
</mapper>
mybatis-config.xml中的映射配置

在configuration标签中添加mappers标签,指定引入了什么xml文件

<mappers>
    <mapper resource="mapper/SmbmsUserMapper.xml"></mapper>
</mappers>
测试方法
 @Test
public void test01(){
    //1.读取核心的配置文件
    String config = "mybatis-config.xml";
    try {
        //2.MyBatis提供了核心的对象Resource对资源进行获取,将xml文件转换为流对象
        InputStream in = Resources.getResourceAsStream(config);
        //3.构建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //4.创建一个会话
        SqlSession session = factory.openSession();
        //5.利用会话完成数据库操作
        Object o = session.selectOne("com.xshiedu.mapper.SmbmsUserMapper.countUser");
        System.out.println(o);
        //6.记得提交事务(因为此处是采用JDBC模式,需要自行管理事务)
        session.commit();
        session.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

MyBatis工具类

在非动态代理中,在测试方法中使用了较为复杂的步骤,但其中步骤1-3中,SqlSessionFactoryBuilder只用于构建SqlSessionFactory,而SqlSessionFactory也只是使用1次,仅仅在需要SqlSession时,才通过openSession的方式进行SqlSession的创建,因而可以通过静态代码块以及静态方法对上述操作进行封装

注意:可以在sqlSessionFactory.openSession方法中添加布尔类型参数,形如sqlSessionFactory.openSession(true),自动提交,用户可不再使用session.commit()方法

package com.xshiedu.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession createSession(){
        //默认关闭连接
        return sqlSessionFactory.openSession();
        //添加后可以不再编写session.commit()
        //return sqlSessionFactory.openSession(true);
    }
    
    public static void closeSession(SqlSession session){
        if(session != null){
            session.close();
        }
    }
}

mapper动态代理(推荐)

Mapper接口开发方法只需要程序员编写Mapper接口,由Mybatis框架根据接口定义创建接口的动态代理对象,代理
Mapper接口开发需要遵循以下规范:

  1. Mapper.xml文件中的namespace与mapper接口的类路径相同。
  2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  3. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
  4. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同(其中mapper.xml中的parameterType参数可以省略)
推荐插件:Free Mybatis Plugin

在使用时mapper动态代理时,可以在IDEA中查找该插件并安装,下载后可以快速跳转到

mapper接口

此处以SmbmsUserMapper为例

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;

import java.util.List;

public interface SmbmsUserMapper {
    int countUser();
}
mapper.xml文件

需要注意的是,动态代理下,namespace的值要求必须是mapper接口的完整类路径,id的值必须是mapper接口中的方法名

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--动态代理模式下,namespace的值要求必须是mapper接口的类路径-->
<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <!--此处的id只要保证该mapper文件中,唯一id即可-->
    <select id="countUser" resultType="java.lang.Integer">
        select count(*) from smbms_user
    </select>
</mapper>

如下图所示,为映射关系,重点理解下图即可

mybatis-config.xml中的映射配置(自由度高)

在configuration标签中添加mappers标签,指定引入了什么xml文件

<mappers>
    <mapper resource="mapper/SmbmsUserMapper.xml"></mapper>
</mappers>
测试方法
@Test
public void test02(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.countUser());
    MybatisUtil.closeSession(session);
}

mappers映射器

在设置好XXXmapper.xml文件后,我们需要将对应的xml映射到对应的mybatis-config.xml配置文件中,通常有如下4种方式使用

方式1:完全限定资源定位符(不推荐)

该方式使用的是文件协议的方式,但是对于一些电脑,可能不存在指定盘符,因而不推荐

<mappers>
   <mapper url="file:///D:/WorkSpace/project/ssm_demo/src/main/resources/mapper/SmbmsUserMapper.xml"/>
</mappers>
方式2:相对类路径资源引用

maven项目推荐使用这种模式,因为无需配置额外参数,只需保证,src/main/resources/mapper资源路径下存在指定的mapper文件即可

<mappers>
   <mapper resource="mapper/SmbmsUserMapper.xml" />
</mappers>
方式3与方式4注意事项

1、对应的xxxMapper.xml必须与对应的接口同名

如:SmbmsUserMapper 与 SmbmsUserMapper.xml

2、对应的xxxMapper.xml必须与对应的接口处于同包

3、方式3与方式4分别为映射器接口实现类的完全限定类名以及扫描包的方式,因为Maven项目如果没有进行特殊的配置,其会按照标准的目录结构查找和处理各种类型文件,有些资源在默认情况下被忽略而不被编译,因而有如下2种解决方案:

方案1:resources标签

通过resources标签标明哪些文件是不能被忽略的,哪些文件是必须排除的

在maven项目中的pom.xml中,添加resources标签,添加后记得 更新一下

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>
方案2:添加maven打包插件

在pom文件中,将如下代码拷贝到pom.xml中,记得不要放在pluginManagement标签中,而是整个拷贝,同理记得要更新一下,最好重新用Maven执行 clean install 指令

<plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
            <execution>
                <id>add-resource</id>
                <phase>generate-resources</phase>
                <goals>
                    <goal>add-resource</goal>
                </goals>
                <configuration>
                    <resources>
                        <resource>
                            <directory>src/main/java</directory>
                            <includes>
                                <include>**/*.xml</include>
                                <include>**/*.properties</include>
                            </includes>
                        </resource>
                        <resource>
                            <directory>src/main/resources</directory>
                            <includes>
                                <include>**/*.xml</include>
                                <include>**/*.properties</include>
                            </includes>
                            <filtering>false</filtering>
                        </resource>
                    </resources>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>
方式3:使用映射器接口实现类的完全限定类名
<mappers>
    <mapper class="com.xshiedu.mapper.SmbmsUserMapper" />
</mappers>
方式4:扫描包方式(方便快捷)

扫描包即将包内的映射器接口实现全部注册为映射,这样一来,该包路径下的所有xml全部配置完毕,后期一般会结合Spring一起使用,实现扫包

<mappers>
    <package name="com.xshiedu.mapper"/>
</mappers>

案例演示

如下的案例采用的均为mapper接口动态代理的方式实现,其中忽略映射器配置

查询总数

SmbmsUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <select id="countUser" resultType="java.lang.Integer">
        select count(*) from smbms_user
    </select>
</mapper>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    int countUser();
}

测试类

@Test
public void test02(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.countUser());
    MybatisUtil.closeSession(session);
}

查询所有

SmbmsUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <select id="queryAll" resultType="SmbmsUser">
        select * from smbms_user
    </select>
</mapper>

SmbmsUserMapper接口

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryAll();
}

测试类

@Test
public void test03(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryAll());
    MybatisUtil.closeSession(session);
}

模糊查询

模糊查询一共有3种实现方式,分别为sql中传统的concat函数、直接传入时带上%%、bind标签等方法

方式1:concat方法(常用)

SmbmsUserMapper.xml

因为是单个参数,实际上此处#{myTestName}随便你写啥,如#{xxx},但最好和入参相同,多个的话则要和入参一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <select id="queryByName" resultType="com.xshiedu.pojo.SmbmsUser">
        select * from smbms_user
        where userName like concat('%',#{userName},'%')
    </select>
</mapper>
SmbmsUserMapper接口

此处可以使用@param注解,虽然不加也可以,但后期推荐添加,与 #{} 中的变量名一致

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryByName(@Param("userName") String userName);
}
测试方法
@Test
public void test04(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryByName("张"));
    MybatisUtil.closeSession(session);
}

方式2:入参直接传入%张%(不推荐)

使用这种方式处理,则需要在用户传入参数时,带上 %张%

SmbmsUserMapper.xml

因为是单个参数,实际上此处#{myTestName}随便你写啥,如#{xxx},但最好和入参相同,多个的话则要和入参一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <select id="queryByName" resultType="com.xshiedu.pojo.SmbmsUser">
        select * from smbms_user
        where userName like #{userName}
    </select>
</mapper>
SmbmsUserMapper接口

此处可以使用@param注解,虽然不加也可以,但后期推荐添加,与 #{} 中的变量名一致

package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryByName(@Param("userName") String userName);
}
测试方法
@Test
public void test04(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryByName("%张%"));
    MybatisUtil.closeSession(session);
}

方式3:bind标签(灵活度高)

使用bind标签,用户可以灵活封装指定参数

SmbmsUserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <select id="queryByName" resultType="com.xshiedu.pojo.SmbmsUser">
        <!-- 此处使用 value="'%'+userName+'%'" 也是可行的 -->
        <bind name="myUserName" value="'%'+#{userName}+'%'"/>
        select * from smbms_user
        where userName like #{myUserName}
    </select>
</mapper>
SmbmsUserMapper接口
package com.xshiedu.mapper;

import com.xshiedu.pojo.SmbmsUser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SmbmsUserMapper {
    List<SmbmsUser> queryByName(@Param("userName") String userName);
}
测试方法
@Test
public void test04(){
    SqlSession session = MybatisUtil.createSession();
    SmbmsUserMapper mapper = session.getMapper(SmbmsUserMapper.class);
    System.out.println(mapper.queryByName("张"));
    MybatisUtil.closeSession(session);
}

指定别名

mybatis-config.xml中通过typeAliases标签来实现别名的指定,其中分为2种类型:单体注册包注册

单体注册

将SmbmsUser类起名为jojo,此时在指定的mapper.xml中的resultType可以使用jojo

mybatis-config.xml

</typeAliases>
    <typeAlias type="com.xshiedu.pojo.SmbmsUser" alias="jojo"/>
</typeAliases>

mapper.xml

<select id="queryAll" resultType="jojo">
    select * from smbms_user
</select>

包注册

使用包注册,此时在com.xshiedu.pojo的所有类,可以直接使用类名且不区分大小写

mybatis-config.xml

</typeAliases>
    <package name="com.xshiedu.pojo"/>
</typeAliases>

mapper.xml

<select id="queryAll" resultType="smbmsuser">
    select * from smbms_user
</select>

注意

单体注册和包注册可以一起使用,

</typeAliases>
    <typeAlias type="com.xshiedu.pojo.SmbmsUser" alias="jojo"/>
    <package name="com.xshiedu.pojo"/>
</typeAliases>

推荐还是用全限定类名,容易排查BUG

<select id="queryAll" resultType="com.xshiedu.pojo.SmbmsUser">
    select * from smbms_user
</select>

额外补充

Mysql8时区问题

pom文件

记得引入最新的mysql连接工具

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>

解决方案1

db.properties

记得mysql8,driver要改为com.mysql.cj.jdbc.Driver

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/PetSys?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=admin

mysql登入管理员dos界面

#查询当前时区
show variables like '%time_zone%';
#在标准时区上加+8小时,即东8区时间
set global time_zone='+8:00';
#刷新权限
flush privileges; 

解决方案2(推荐)

记得mysql8,driver要改为com.mysql.cj.jdbc.Driver

如果方案2不行则使用方案1

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/PetSys?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=admin

非动态Mapper代理方式中3个常用方法

selectOne()

selectOne返回值为Object

mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--在非动态代理模式下,namespace的值可以随意填写,只要保证唯一即可-->
<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <!--此处的id只要保证该mapper文件中,唯一id即可-->
    <select id="countUser" resultType="java.lang.Integer">
        select count(*) from smbms_user
    </select>
</mapper>
mybatis-config.xml中的映射配置

在configuration标签中添加mappers标签,指定引入了什么xml文件

<mappers>
    <mapper resource="mapper/SmbmsUserMapper.xml"></mapper>
</mappers>
测试方法
@Test
public void test02(){
    SqlSession session = MybatisUtil.createSession();
    Object o = session.selectOne("com.xshiedu.mapper.SmbmsUserMapper.countUser");
    System.out.println(o);
    MybatisUtil.closeSession(session);
}

selectList()

selectList返回值为List,即List泛型集合

mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--在非动态代理模式下,namespace的值可以随意填写,只要保证唯一即可-->
<mapper namespace="com.xshiedu.mapper.SmbmsUserMapper">
    <!--此处的id只要保证该mapper文件中,唯一id即可-->
    <select id="getAll" resultType="java.lang.SmbmsUser">
        select * from smbms_user
    </select>
</mapper>
mybatis-config.xml中的映射配置

在configuration标签中添加mappers标签,指定引入了什么xml文件

<mappers>
    <mapper resource="mapper/SmbmsUserMapper.xml"></mapper>
</mappers>
测试方法
@Test
public void test02(){
    SqlSession session = MybatisUtil.createSession();
    List<User> list  = session.selectList("com.xshiedu.mapper.SmbmsUserMapper.getAll");
    System.out.println(list);
	MybatisUtil.closeSession(session);
}

selectMap()

selectMap返回值为Map<K,V>,即Map泛型集合

mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<select id="queryByName" resultType="com.xshiedu.pojo.SmbmsUser">
    <bind name="myUserName" value="'%'+userName+'%'"/>
    select * from smbms_user
    where userName like #{myUserName}
</select>
mybatis-config.xml中的映射配置

在configuration标签中添加mappers标签,指定引入了什么xml文件

<mappers>
    <mapper resource="mapper/SmbmsUserMapper.xml"></mapper>
</mappers>
测试方法
@Test
public void test05(){
    SqlSession session = MybatisUtil.createSession();
    /*Map<String> map = new */
    //第2个参数表示查询条件,多个可以用Map集合或者自定义VO表示
    //第3个参数表示封装好后的Map集合中的key使用的是查询出来的实体类中哪一个属性,比如此处以SmbmsUser的id作为key,所以写"id"
    Map<Object, Object> map = session.selectMap("com.xshiedu.mapper.SmbmsUserMapper.queryByName", "张", "id");
    System.out.println(map);
    MybatisUtil.closeSession(session);
}
结果打印
{
6=TpApiConfig{id='6'userCode='zhanghua'userName='张华'userPassword='0000000'gender='1'birthday='Wed Jun 15 00:00:00 CST 1983'phone='13544561111'address='北京市海淀区学院路61号'userRole='3'createdBy='1'creationDate='Mon Feb 11 10:51:17 CST 2013'modifyBy='null'modifyDate='null'}, 
12=TpApiConfig{id='12'userCode='zhangchen'userName='张晨'userPassword='0000000'gender='1'birthday='Fri Mar 28 00:00:00 CST 1986'phone='18098765434'address='朝阳区管庄路口北柏林爱乐三期13号楼'userRole='3'createdBy='1'creationDate='Tue Aug 09 05:52:37 CST 2016'modifyBy='1'modifyDate='Thu Apr 14 14:15:36 CST 2016'}
}

反向生成配置文件

Generate POJOs.groovy

import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil
import java.io.*
import java.text.SimpleDateFormat

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

packageName = "com.xshiedu.pojo;"
typeMapping = [
        (~/(?i)int/)                         : "Integer",
        (~/(?i)long/)                        : "Long",
        (~/(?i)float|double|decimal|real/)   : "Double",
        (~/(?i)date|datetime|timestamp|time/): "Date",
        (~/(?i)/)                            : "String"
]

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
  SELECTION.filter { it instanceof DasTable }.each { generate(it, dir) }
}

def generate(table, dir) {
  def className = javaName(table.getName(), true)
//    def className = javaClassName(table.getName(), true)
  def fields = calcFields(table)
  packageName = getPackageName(dir)
  PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(dir, className + ".java")), "UTF-8"))
  printWriter.withPrintWriter { out -> generate(out, className, fields, table) }
}

// 获取包所在文件夹路径
def getPackageName(dir) {
  return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "") + ";"
}

def generate(out, className, fields, table) {
  out.println "package $packageName"
  out.println ""
//    out.println "import javax.persistence.Column;"
//    out.println "import javax.persistence.Entity;"
//    out.println "import javax.persistence.Table;"
  out.println "import java.io.Serializable;"
  Set types = new HashSet()

  fields.each() {
    types.add(it.type)
  }

  if (types.contains("Date")) {
    out.println "import java.util.Date;"
  }

  if (types.contains("InputStream")) {
    out.println "import java.io.InputStream;"
  }
  out.println ""
  out.println "/**"
  out.println " * @Author FangLaoC"
  out.println " * @Date " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())
  out.println " */"
  out.println ""
//    out.println "@Entity"
//    out.println "@Table ( name =\"" + table.getName() + "\" )"
  out.println "public class $className  implements Serializable {"
  out.println ""
  out.println genSerialID()
  fields.each() {
    out.println ""
    // 输出注释
    if (isNotEmpty(it.commoent)) {
      out.println "\t/**"
      out.println "\t * ${it.commoent.toString()}"
      out.println "\t */"
    }

    if (it.annos != "") out.println "   ${it.annos.replace("[@Id]", "")}"

    // 输出成员变量
    out.println "\tprivate ${it.type} ${it.name};"
  }
  out.println ""


  // 输出get/set方法
  fields.each() {
    out.println ""
    out.println "\tpublic ${it.type} get${it.name.capitalize()}() {"
    out.println "\t\treturn this.${it.name};"
    out.println "\t}"
    out.println ""

    out.println "\tpublic void set${it.name.capitalize()}(${it.type} ${it.name}) {"
    out.println "\t\tthis.${it.name} = ${it.name};"
    out.println "\t}"
  }

  // 输出toString方法
  out.println ""
  out.println "\t@Override"
  out.println "\tpublic String toString() {"
  out.println "\t\treturn \"TpApiConfig{\" +"
  fields.each() {
    out.println "\t\t\t\t\"${it.name}='\" + ${it.name} + '\\'' +"
  }
  out.println "\t\t\t\t'}';"
  out.println "\t}"

  out.println ""
  out.println "}"
}

def calcFields(table) {
  DasUtil.getColumns(table).reduce([]) { fields, col ->
    def spec = Case.LOWER.apply(col.getDataType().getSpecification())

    def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
    def comm = [
            colName : col.getName(),
            name    : javaName(col.getName(), false),
            type    : typeStr,
            commoent: col.getComment(),
//                annos   : "\t@Column(name = \"" + col.getName() + "\" )"
            annos   : ""
    ]
//        if ("id".equals(Case.LOWER.apply(col.getName())))
//            comm.annos += ["@Id"]
    fields += [comm]
  }
}

// 处理类名(这里是因为我的表都是以t_命名的,所以需要处理去掉生成类名时的开头的T,
// 如果你不需要那么请查找用到了 javaClassName这个方法的地方修改为 javaName 即可)
def javaClassName(str, capitalize) {
  def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
          .collect { Case.LOWER.apply(it).capitalize() }
          .join("")
          .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
  s = s[1..s.size() - 1]
  capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def javaName(str, capitalize) {
  def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str)
          .collect { Case.LOWER.apply(it).capitalize() }
          .join("")
          .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
  capitalize || s.length() == 1 ? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def isNotEmpty(content) {
  return content != null && content.toString().trim().length() > 0
}

static String changeStyle(String str, boolean toCamel) {
  if (!str || str.size() <= 1)
    return str

  if (toCamel) {
    String r = str.toLowerCase().split('_').collect { cc -> Case.LOWER.apply(cc).capitalize() }.join('')
    return r[0].toLowerCase() + r[1..-1]
  } else {
    str = str[0].toLowerCase() + str[1..-1]
    return str.collect { cc -> ((char) cc).isUpperCase() ? '_' + cc.toLowerCase() : cc }.join('')
  }
}

static String genSerialID() {
  return "\tprivate static final long serialVersionUID =  " + Math.abs(new Random().nextLong()) + "L;"
}