• MyBatis配置使用详解


    MyBatis配置使用详解

    更多详细配置可参考:MyBatis官方文档

    文章目录

    1. 什么是MyBatis

    MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis。代码于 2013年11月迁移到Github。

    官方文档的描述:

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

    总的来说MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架

    2. 搭建MyBaits

    下载地址:https://github.com/mybatis/mybatis-3

    2.1 初始化工程

    1. 使用idea创建一个maven工程

    2. 引入相关依赖(这里使用MyBatis3.5.7)

      <dependencies>
              <!-- Mybatis核心 -->
              <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.5.7</version>
              </dependency>
              <!-- junit测试 -->
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
                  <scope>test</scope>
              </dependency>
              <!-- MySQL驱动 -->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.3</version>
              </dependency>
      </dependencies>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    3. 创建并编写配置文件

    每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

    从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。

    String resource = "org/mybatis/example/mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    • 1
    • 2
    • 3

    XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。

    配置文件示例:

    配置文件名称可以自定义,但是建议使用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">
    <configuration>
      <environments default="development">
        <environment id="development">
          <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>
      <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
      </mappers>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.2 创建数据表

    DROP TABLE IF EXISTS `t_user`;
    CREATE TABLE `t_user`  (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      `age` int(11) NULL DEFAULT NULL,
      `email` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3 创建实体类对象(POJO)

    public class User {
        private Integer id;
        
        private String username;
        
        private String password;
        
        private String sex;
        
        private Integer age;
        
        private String email;
    	
    	constructor...
    	
    	set and get ...
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.4 创建Mapper接口

    Mapper接口相当于原来的Dao,但是不需要我们手动编写其实现类。但是需要配置对应的xml文件,这是因为MyBatis在底层通过反射读取xml文件在程序运行时动态为我们生成了实现类。

    public interface UserMapper {
        int insertUser(User user);
    }
    
    • 1
    • 2
    • 3

    2.5 创建MyBatis的映射文件

    1、映射文件命名规则

    表所对应的实体类的类名+Mapper.xml,例如:UserMapper.java -> UserMapper.xml

    2、Mapper文件作用

    用于编写SQL语句,实现对数据库的操作。

    3、MyBatis中可以面向接口操作数据,要保证两个一致

    1. mapper接口的全类名和映射文件的命名空间(namespace)保持一致
    2. mapper接口中方法的方法名和映射文件中编写SQL的标签的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">
    <mapper namespace="com.jc.mybatis.mapper.UserMapper">
        <insert id="insertUser">
            insert into t_user values(null, "admin", "123123", "男", 18, "2307491719@qq.com")
        </insert>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.6 引入日志框架

    1. 引入依赖

      <!--引入日志-->
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.25</version>
      </dependency>
      
      <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
      </dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    2. 在resources文件夹下添加log4j.properties文件

      # resources文件夹根目录下
      ### 配置根
      log4j.rootLogger = debug,console
      
      ### 日志输出到控制台显示
      log4j.appender.console=org.apache.log4j.ConsoleAppender
      log4j.appender.console.Target=System.out
      log4j.appender.console.layout=org.apache.log4j.PatternLayout
      log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    2.7 测试

    创建测试类:

    import com.jc.mybatis.mapper.UserMapper;
    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 org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class MyBatisTest {
        @Test
        public void testInsertUser() throws IOException {
            // 获取输入流
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            // 创建sqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 创建SqlSession工厂
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            // 获取SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 获取Mapper对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            int result = userMapper.insertUser();
            // 因为默认的事务管理器时JDBC,所以需要手动提交事务
            sqlSession.commit();
            System.out.println("result = " + result);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    输出:

    result = 1
    
    • 1

    3. MyBatis核心配置文件解析

    要注意以下标签在MyBatis配置文件中是有配置顺序的。

    配置顺序如下

    1. properties
    2. settings
    3. typeAliases
    4. typeHandlers
    5. objectFactory
    6. objectWrapperFactory
    7. reflectorFactory
    8. plugins?,environments
    9. databaseIdProvider
    10. mappers
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.1 environment

    <!--
        environments:设置多个连接数据库的环境
        default:默认使用某个数据库环境
     -->
    <environments default="development">
        <!--
           environment:设置具体的连接数据库的环境信息
           属性:
               id:设置环境的唯一标识,可通过environments标签中的default设置某一个环境的id,表示默认使用的环境
        -->
        <environment id="development">
            <!--
                transactionManager:设置事务管理方式
                属性:
                    type:设置事务管理方式,type="JDBC|MANAGED"
                    type="JDBC":设置当前环境的事务管理都必须手动处理
                    type="MANAGED":设置事务被管理,例如spring中的AOP
            -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3.2 properties

    用于引入Properties文件。

    使用举例:

    我们将数据库配置信息配置到properties文件中,通过properties标签引入。

    <properties resource="jdbc.properties"/>
    
    • 1

    jdbc.properties配置文件:

    jdbc.driver = com.mysql.jdbc.Driver
    jdbc.url = jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8
    jdbc.username = root
    jdbc.password = 123456
    
    • 1
    • 2
    • 3
    • 4

    3.3 typeAliases

    用于配置mapper文件中类型别名。

    type:要指定别名的类型的全类名

    alias: 别名,如果不指定alias的值,默认是类名,并且不区分大小写

    <typeAliases>
        <typeAlias type="com.jc.mybatis.pojo.User" alias="User"/>
    </typeAliases>
    
    • 1
    • 2
    • 3

    也可以以包为单位设置别名:这时的别名默认就是不区分大小写的类名

    <typeAliases>
        <package name="com.jc.mybatis.pojo"/>
    </typeAliases>
    
    • 1
    • 2
    • 3

    mapper文件中可以这样写:

    <select id="getAllUsers" resultType="user">
        select * from t_user
    </select>
    
    • 1
    • 2
    • 3

    3.4 mappers

    用于引入mapper文件。

    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
        <mapper resource="mappers/XxxMapper.xml"/>
        ...
    </mappers>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也可以以包为单位引入mapper文件:

    但是要注意:此方式必须保证mapper接口和mapper映射文件必须在相同的包下

    <mappers>
        <package name="com.jc.mybatis.mapper"/>
    </mappers>
    
    • 1
    • 2
    • 3

    4. MyBatis获取参数值的两种方式 #{} 和 ${}

    • MyBatis获取参数值的两种方式:${}#{}
    • #{} 的本质就是占位符取值,${} 的本质就是字符串拼接。
    • ${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。

    先来复习一下JDBC中sql的使用操作:

    @Test
    public void testJDBC() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String username = "Tom";
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8", "root", "123456");
    
        PreparedStatement preparedStatement = conn.prepareStatement("select * from t_user where username = ?");
        preparedStatement.setString(1, username);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里是使用占位符的方式,也就是#{}。那么使用字符串拼接的方式就是${}

    下面来举例在MyBatis使用时参数的情况。

    4.1 单个字面量类型的参数

    若mapper接口中的方法参数为单个的字面量类型
    此时可以使用${}#{}以任意的名称获取参数的值,注意${}需要手动加单引号

    <select id="selectUserByUsername" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username = #{username}
    </select>
    
    同样可以执行
    <select id="selectUserByUsername" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username = #{xxx} 
    </select>
    
    使用${}需要加上单引号
    <select id="selectUserByUsername" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username = '${usename}'
    </select>
    
    同样可以执行
    <select id="selectUserByUsername" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username = '${yyy}'
    </select>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4.2 多个字面量类型的参数

    若mapper接口中的方法参数为多个时此时MyBatis会自动将这些参数放在一个map集合中 ,以arg0,arg1…为键,以参数为值;以param1,param2…为键,以参数为值;因此只需要通过${}#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。

    可以运行:
    <select id="selectUserByUsernameAndPassword" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username=#{param1} and password = #{param2}
    </select>
    
    <select id="selectUserByUsernameAndPassword" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username='${param1}' and password = '${param2}'
    </select>
    
    报错:
    <select id="selectUserByUsernameAndPassword" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username='${username}' and password = '${password}'
    </select>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.3 map集合类型的参数

    若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中只需要通过 ${}#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。

    <select id="selectUserByMap" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username=#{username} and password = #{password}
    </select>
    
    • 1
    • 2
    • 3
    @Test
    public void test3() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map map = new HashMap<String, String>();
        map.put("username", "Tom");
        map.put("password", "123456");
        User user = mapper.selectUserByMap(map);
        System.out.println("user = " + user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.4 实体类类型的参数

    若mapper接口中的方法参数为实体类对象时此时可以使用${}#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号。

    <insert id="save">
        insert into t_user values(null, #{username}, #{password}, #{sex}, #{age}, #{email})
    </insert>
    
    • 1
    • 2
    • 3
    @Test
    public void test4() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setUsername("admin");
        user.setPassword("888888");
        user.setSex("男");
        user.setAge(11);
        user.setEmail("admin@gmail.com");
    
        int save = mapper.save(user);
        System.out.println("save = " + save);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.5 使用@Param注解标识参数

    可以通过@Param注解标识mapper接口中的方法参数。

    此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以 param1,param2…为键,以参数为值;只需要通过${}#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。

    User selectByUsername(@Param("username") String username);
    
    • 1
    <select id="selectByUsername" resultType="com.jc.mybatis.pojo.User">
        select * from t_user where username = #{username}
    </select>
    
    • 1
    • 2
    • 3

    5. MyBatis的各种查询功能

    5.1 查询一个实体类对象

    /**
    * 根据用户id查询用户信息
    * @param id
    * @return
    */
    User getUserById(@Param("id") int id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--User getUserById(@Param("id") int id);-->
    <select id="getUserById" resultType="User">
    	select * from t_user where id = #{id}
    </select>
    
    • 1
    • 2
    • 3
    • 4

    5.2 查询一个List集合

    /**
    * 查询所有用户信息
    * @return
    */
    List<User> getUserList();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <!--List<User> getUserList();-->
    <select id="getUserList" resultType="User">
    	select * from t_user
    </select>
    
    • 1
    • 2
    • 3
    • 4

    5.3 查询单个数据

    /**
    * 查询用户的总记录数
    * @return
    * 在MyBatis中,对于Java中常用的类型都设置了类型别名
    * 例如:java.lang.Integer-->int|integer
    * 例如:int-->_int|_integer
    * 例如:Map-->map,List-->list
    */
    int getCount();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <!--int getCount();-->
    <select id="getCount" resultType="_integer">
    	select count(id) from t_user
    </select>
    
    • 1
    • 2
    • 3
    • 4

    5.4 查询一条数据为map集合

    /**
    * 根据用户id查询用户信息为map集合
    * @param id
    * @return
    */
    Map<String, Object> getUserToMap(@Param("id") int id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--Map<String, Object> getUserToMap(@Param("id") int id);-->
    <select id="getUserToMap" resultType="map">
    	select * from t_user where id = #{id}
    </select>
    <!--结果:{password=123456, sex=男, id=1, age=23, username=admin}-->
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.5 查询多条数据为map集合

    方式一:

    /**
    * 查询所有用户信息为map集合
    * @return
    * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取
    */
    List<Map<String, Object>> getAllUserToMap();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--Map<String, Object> getAllUserToMap();-->
    <select id="getAllUserToMap" resultType="map">
    	select * from t_user
    </select>
    
    • 1
    • 2
    • 3
    • 4

    方式二:

    /**
    * 查询所有用户信息为map集合
    * @return
    * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并
    且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的
    map集合
    */
    @MapKey("id")
    Map<String, Object> getAllUserToMap();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <!--Map<String, Object> getAllUserToMap();-->
    <select id="getAllUserToMap" resultType="map">
    	select * from t_user
    </select>
    结果:
    <!--
    {
        1={password=123456, sex=男, id=1, age=23, username=admin},
        2={password=123456, sex=男, id=2, age=23, username=张三},
        3={password=123456, sex=男, id=3, age=23, username=张三}
    } 
    -->
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6. 特殊SQL的执行

    6.1 模糊查询

    /**
    * 测试模糊查询
    * @param mohu
    * @return
    */
    List<User> testMohu(@Param("mohu") String mohu);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--List<User> testMohu(@Param("mohu") String mohu);-->
    <select id="testMohu" resultType="User">
        <!--select * from t_user where username like '%${mohu}%'-->
        <!--select * from t_user where username like concat('%',#{mohu},'%')-->
        select * from t_user where username like "%"#{mohu}"%"
    </select>
    
    上面三种都可以使用,最后一种使用的最多,本质上是字符串拼接的问题。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    6.2 批量删除

    /**
    * 批量删除
    * @param ids
    * @return
    */
    int deleteMore(@Param("ids") String ids);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--int deleteMore(@Param("ids") String ids);-->
    <delete id="deleteMore">
    	delete from t_user where id in (${ids})
    </delete>
    
    • 1
    • 2
    • 3
    • 4

    只能使用${},不能使用#{},因为#{}会自动拼接单引号,sql语句就会变成这样:delete from t_user where id in ('1,2,3'),这样的SQL语句执行是没有效果的,所以只能使用${}

    6.3 动态设置表名

    /**
    * 动态设置表名,查询所有的用户信息
    * @param tableName
    * @return
    */
    List<User> getAllUser(@Param("tableName") String tableName);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    <!--List<User> getAllUser(@Param("tableName") String tableName);-->
    <select id="getAllUser" resultType="User">
    	select * from ${tableName}
    </select>
    
    • 1
    • 2
    • 3
    • 4

    只能使用${},因为表名不可以加单引号,因为#{}会自动加上单引号。

    6.4 添加功能获取自增的主键

    场景举例:假如我们要操作的两张表是1对多的关系的,比如学生表和班级表。我们新添加一个班级,同时想为这个班级添加一些学生信息。而添加学生信息的学生表中就有一个字段是班级表的主键id,所以需要获取这个班级id。

    /**
    * 添加用户信息
    * @param user
    * @return
    * useGeneratedKeys:设置使用自增的主键
    * keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中
    */
    int insertUser(User user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    <!--int insertUser(User user);-->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    	insert into t_user values(null,#{username},#{password},#{age},#{sex})
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 需要将useGeneratedKeys设置为true
    • 通过设置keyProperty属性的值就可以将自增主键的值设置到传入参数对象中的属性中。

    7. 自定义映射resultMap

    在实际使用MyBaits操作数据时会遇到一个问题:数据表的字段名和实体类的属性名不一致。

    如果不解决这个问题,查询出来的字段值就是null

    例如:

    员工信息表t_emp,表示员工名字的字段是emp_name,而实体类的属性是empName。

    解决方案一:

    在编写SQL语句的时候为不同的字段起别名:

    select eid, emp_name `empName`, age, sex, email, did from t_emp;
    
    • 1

    解决方案二:

    通过配置MyBatis配置文件开启自动将下划线命名的规则转换为驼峰命名规则。

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    • 1
    • 2
    • 3

    更多可以参考官方文档:https://mybatis.org/mybatis-3/zh/configuration.html#settings

    解决方案三:

    使用resultMapresultMap处理字段和属性的映射关系。

    7.1 resultMap处理字段和属性的映射关系

    <!--
        resultMap:设置自定义映射
        属性:
        id:表示自定义映射的唯一标识
        type:查询的数据要映射的实体类的类型
        子标签:
        id:设置主键的映射关系
        result:设置普通字段的映射关系
        association:设置多对一的映射关系
        collection:设置一对多的映射关系
        属性:
        property:设置映射关系中实体类中的属性名
        column:设置映射关系中表中的字段名
    -->
    
    <resultMap id="empResultMap" type="com.jc.mybatis.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="email" column="email"></result>
        <result property="sex" column="sex"></result>
        <result property="age" column="age"></result>
    </resultMap>
    
    <select id="getAllEmp" resultMap="empResultMap">
        select * from t_emp
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    7.2 多对一映射处理

    一个部门中有多个员工,所以员工与部门的关系就是多对一。

    想要查询员工信息时,想要把相对应的部门信息也查出来就需要在实体类中添加一个部门类类型的属性。

    例如:

    public class Emp {
        private int eid;
    
        private String empName;
    
        private int age;
    
        private String sex;
    
        private String email;
    
        // 用于存储部门信息
        private Dept dept;
        
        // set and get ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.2.1 级联方式处理映射关系

    <resultMap id="empAndDeptResultMapOne" type="com.jc.mybatis.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <result property="age" column="age"></result>
        <!--级联赋值-->
        <result property="dept.did" column="did"></result>
        <result property="dept.deptName" column="dept_name"></result>
    </resultMap>
    
    <select id="getEmpAndDeptById" resultMap="empAndDeptResultMapOne">
        select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.2.2 使用association标签处理映射关系

    <resultMap id="empAndDeptResultMapTwo" type="com.jc.mybatis.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <result property="age" column="age"></result>
        <!--
        association: 
               property: 属性名
               javaType: 属性对应的类型
        -->
        <association property="dept" javaType="com.jc.mybatis.pojo.Dept">
            <result property="did" column="did"></result>
            <result property="deptName" column="dept_name"></result>
        </association>
    </resultMap>
    
    <select id="getEmpAndDeptById" resultMap="empAndDeptResultMapTwo">
        select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    7.2.3 分步查询处理

    原理是MyBatis使用用association标签中的select属性设置另一个查询用的方法组装的方式分步查询。先查出员工信息,在通过查出员工表中的部门id查询对应的部门信息。

    分布查询有一个好处,就是延迟加载

    EmpMapper.xml:

    <resultMap id="getEmpAndDeptByStepOneResultMap" type="com.jc.mybatis.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <result property="age" column="age"></result>
        <association property="dept" select="com.jc.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did">
        </association>
    </resultMap>
    
    <select id="getEmpAndDeptByStepOne" resultMap="getEmpAndDeptByStepOneResultMap">
        select * from t_emp where eid = #{eid}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    DeptMapper.xml:

    <select id="getEmpAndDeptByStepTwo" resultType="com.jc.mybatis.pojo.Dept">
        select * from t_dept where did = #{did}
    </select>
    
    • 1
    • 2
    • 3

    EmpMapper.java中的方法:

    Emp getEmpAndDeptByStepOne(@Param("eid") Integer id);
    
    • 1

    DeptMapper.java中的方法:

    Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
    
    • 1

    查询结果:

    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepOne:137 - ==>  Preparing: select * from t_emp where eid = ?
    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepOne:137 - ==> Parameters: 2(Integer)
    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepTwo:137 - ====>  Preparing: select * from t_dept where did = ?
    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepTwo:137 - ====> Parameters: 1(Integer)
    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepTwo:137 - <====      Total: 1
    2022-06-23 14:46:01 DEBUG getEmpAndDeptByStepOne:137 - <==      Total: 1
    Emp{eid=2, empName='李四', age=22, sex='女', email='123@qq.com', dept=Dept{did=1, deptName='A'}}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    延迟加载功能

    要实现延迟加载需要在配置文件红设置全局配置信息:

    lazyLoadingEnabled: 延迟加载的全局开关。当开启时,所有关联的对象都会延迟加载。

    aggressiveLazyLoading: 当开启时,任何方法的调用都会加载该对象的所有属性。否则每个属性都会按需加载。

    此时就可以实现按需加载,获取的数据时什么,就只会执行响应的sql。

    但是可以通过association或collection标签中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)| eager(立即加载)”

    MyBatis配置文件:

    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    
    • 1
    • 2
    • 3

    EmpMapper.xml中的resultMap:

    <resultMap id="getEmpAndDeptByStepOneResultMap" type="com.jc.mybatis.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
        <result property="age" column="age"></result>
        <association fetchType="lazy" property="dept" select="com.jc.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did">
        </association>
    </resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出:

    可以发现只有一条查询记录,如果将fetchType的值设置为eager,就会关闭懒加载,也就是一次性把关联的属性都查询出来。

    2022-06-23 15:11:07 DEBUG getEmpAndDeptByStepOne:137 - ==>  Preparing: select * from t_emp where eid = ?
    2022-06-23 15:11:07 DEBUG getEmpAndDeptByStepOne:137 - ==> Parameters: 2(Integer)
    2022-06-23 15:11:07 DEBUG getEmpAndDeptByStepOne:137 - <==      Total: 1
    李四
    
    • 1
    • 2
    • 3
    • 4

    7.3 一对多映射处理

    一个部门对应了多个员工,在数据库中是在员工表中添加关于部门id的冗余字段来实现依赖关系。而在Java的实体类中使用集合的方式进行存储。

    例如:

    public class Dept {
        private int did;
    
        private String deptName;
    
        private List<Emp> emps;
     	
        // set and get ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7.3.1 使用collection标签

    DeptMapper.xml:

    使用collection标签来设置集合,ofType属性来指定集合中元素的类型。

    <resultMap id="deptAndEmpResultMap" type="com.jc.mybatis.pojo.Dept">
        <id property="did" column="did"></id>
        <result property="deptName" column="dept_name"></result>
        
        <collection property="emps" ofType="com.jc.mybatis.pojo.Emp">
            <id property="eid" column="eid"></id>
            <result property="empName" column="emp_name"></result>
            <result property="sex" column="sex"></result>
            <result property="age" column="age"></result>
            <result property="email" column="email"></result>
        </collection>
    </resultMap>
    
    <select id="getDeptAndEmpById" resultMap="deptAndEmpResultMap">
        select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.3.2 分布查询处理

    DeptMapper.xml:

    <resultMap id="dptAndEmpByStepResultMap" type="com.jc.mybatis.pojo.Dept">
        <id property="did" column="did"></id>
        <result property="deptName" column="dept_name"></result>
        <collection
                select="com.jc.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                property="emps"
                column="did">
            <id property="eid" column="eid"></id>
            <result property="empName" column="emp_name"></result>
            <result property="sex" column="sex"></result>
            <result property="age" column="age"></result>
            <result property="email" column="email"></result>
        </collection>
    </resultMap>
    
    <select id="getDeptAndEmpByStepOne" resultMap="dptAndEmpByStepResultMap">
        select * from t_dept where did = #{did}
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    EmpMapper.xml:

    <select id="getDeptAndEmpByStepTwo" resultType="com.jc.mybatis.pojo.Emp">
        select * from t_emp where did = #{did}
    </select>
    
    • 1
    • 2
    • 3

    DeptMapper.java:

    Dept getDeptAndEmpByStepOne(@Param("did") Integer id);
    
    • 1

    EmpMapper.java:

    Emp getDeptAndEmpByStepTwo(@Param("did") Integer did);
    
    • 1

    8. 动态SQL

    Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。

    8.1 if

    if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。

    但是需要注意,如果没有一个条件成立,sql语句可能会拼接上一个and,导致报错。

    所以可以拼接一个 1=1。

    <select id="getEmpListByMoreTJ" resultType="Emp">
        select * from t_emp where 1=1
        <if test="ename != '' and ename != null">
        	and emp_name = #{empName}
        </if>
        <if test="age != '' and age != null">
        	and age = #{age}
        </if>
        <if test="sex != '' and sex != null">
        	and sex = #{sex}
        </if>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    8.2 where

    where和if一般结合使用:
    a> 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
    b> 若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的and去掉
    注意:where标签不能去掉条件最后多余的and

    <select id="getEmpListByMoreTJ2" resultType="Emp">
        select * from t_emp
        <where>
            <if test="ename != '' and ename != null">
            	emp_name = #{empName}
            </if>
            <if test="age != '' and age != null">
            	and age = #{age}
            </if>
            <if test="sex != '' and sex != null">
            	and sex = #{sex}
            </if>
        </where>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8.3 trim

    trim用于去掉或添加标签中的内容。
    常用属性:

    • prefix:在trim标签中的内容的前面添加某些内容。
    • prefixOverrides:在trim标签中的内容的前面去掉某些内容。
    • suffix:在trim标签中的内容的后面添加某些内容。
    • suffixOverrides:在trim标签中的内容的后面去掉某些内容 。
    <select id="getEmpListByMoreTJ" resultType="Emp">
    	select * from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="ename != '' and ename != null">
            	emp_name = #{empName} and
            </if>
            <if test="age != '' and age != null">
            	age = #{age} and
            </if>
            <if test="sex != '' and sex != null">
            	sex = #{sex}
            </if>
        </trim>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8.4 choose、when、otherwise

    choose、when、otherwise是一套标签,需要配合使用。

    注意:使用时至少需要一个when,最多可以有一个otherwise。

    <select id="getEmpListByChoose" resultType="Emp">
        select <include refid="empColumns"></include> from t_emp
        <where>
            <choose>
                <when test="ename != '' and ename != null">
                	emp_name = #{empName}
                </when>
                <when test="age != '' and age != null">
                	age = #{age}
                </when>
                <when test="sex != '' and sex != null">
                	sex = #{sex}
                </when>
                <when test="email != '' and email != null">
                	email = #{email}
                </when>
            </choose>
        </where>
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    8.5 foreach

    适用于批量操作,如批量添加或者批量删除。

    属性:
    collection:设置要循环的数组或集合。
    item:表示集合或数组中的每一个数据。
    separator:设置循环体之间的分隔符。
    open:设置foreach标签中的内容的开始符。
    close:设置foreach标签中的内容的结束符。

    使用举例:

    批量删除:

    EmpMapper.java中的方法:

    int deleteEmpBatch(@Param("eids") Integer[] eids);
    
    • 1
    <delete id="deleteEmpBatch">
        delete from t_emp where eid in
        <foreach collection="eids" item="eid" separator="," open="(" close=")">
            #{eid}
        </foreach>
    </delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    批量添加:

    EmpMapper.java中的方法:

    int insertEmpBatch(@Param("emps") List<Emp> emps);
    
    • 1
    <insert id="insertEmpBatch">
        insert into t_emp values
        <foreach collection="emps" item="emp" separator=",">
            (null, #{emp.empName}, #{emp.age}, #{emp.sex}, #{emp.email}, null)
        </foreach>
    </insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    8.6 sql

    用于编写一个sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入。

    使用举例:

    <sql id="empColumns">
        eid,emp_name,age,sex,email,did
    </sql>
    
    <select id="getAllEmp" resultMap="empResultMap">
        select
         <include refid="empColumns"></include>
        from t_emp
    </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    9. MyBatis的缓存

    9.1 MyBatis的一级缓存

    一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存 ,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

    在MyBatis操作数据库时会创建一个sqlSession,在这个sqlSession中有一个map集合,用于存放缓存数据。

    使一级缓存失效的4种情况:

    1. 不同的SqlSession对应不同的一级缓存
    2. 同一个SqlSession但是查询条件不同
    3. 同一个SqlSession两次查询期间执行了任何一次增删改操作(commit操作)
    4. 同一个SqlSession两次查询期间手动清空了缓存

    9.2 MyBatis的二级缓存

    二级缓存是SqlSessionFactory级别 ,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

    开启二级缓存的条件:

    1. xml配置文件配置
    <settings>
        <!-- 开启二级缓存(默认就是开启状态,但是方便维护,显式写出来 -->
        <setting name="cacheEnabled" value="true" />
    </settings>
    
    • 1
    • 2
    • 3
    • 4
    1. 需要在mapper映射文件写入<cache/>标签
    <!-- 开启本mapper所在namespace的二级缓存 -->
    <cache />
    
    • 1
    • 2
    1. 需要将pojo实现Serializable接口。为了取出实现反序列化操作,因为二级缓存的方式可能有多种,存放到内存中或是写入到磁盘上。
    2. 二级缓存必须在SqlSession关闭或者提交之后有效。

    使二级缓存失效的情况:

    两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。

    9.3 二级缓存的相关配置

    在mapper配置文件中添加的cache标签可以设置一些属性:

    • eviction属性:缓存回收策略,默认的是 LRU。
      • LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
      • FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
      • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
      • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    • flushInterval属性:刷新间隔,单位毫秒
      • 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
    • size属性:引用数目,正整数
      • 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
    • readOnly属性:只读,true/false
      • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
      • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

    9.4 MyBatis缓存的查询顺序

    1. 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
    2. 如果二级缓存没有命中,再查询一级缓存。
    3. 如果一级缓存也没有命中,则查询数据库。
    4. SqlSession关闭之后,一级缓存中的数据会写入二级缓存。

    9.5 整合第三方缓存EHCache

    注意: 整合的第三方缓存只能用于替换二级缓存。

    1、导入相关依赖

    <!-- Mybatis EHCache整合包 -->
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.2.1</version>
    </dependency>
    <!-- slf4j日志门面的一个具体实现 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2、创建EHCache的配置文件ehcache.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
        <!-- 磁盘保存路径 -->
        <diskStore path="E:\MyBatis\ehcache"/>
        <defaultCache
                maxElementsInMemory="1000"
                maxElementsOnDisk="10000000"
                eternal="false"
                overflowToDisk="true"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
        </defaultCache>
    </ehcache>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、设置二级缓存的类型

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
    • 1

    4、加入加入logback日志

    存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml。

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="true">
        <!-- 指定日志输出的位置 -->
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <!-- 日志输出的格式 -->
                <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
                <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
                    [%msg]%n
                </pattern>
            </encoder>
        </appender>
        <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
        <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
        <root level="DEBUG">
            <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
            <appender-ref ref="STDOUT"/>
        </root>
        <!-- 根据特殊需求指定局部日志级别 -->
        <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    5、EHCache配置文件说明

    属性名是 否 必 须作用
    maxElementsInMemory在内存中缓存的element的最大数目
    maxElementsOnDisk在磁盘上缓存的element的最大数目,若是0表示无 穷大
    eternal设定缓存的elements是否永远不过期。 如果为 true,则缓存的数据始终有效, 如果为false那么还 要根据timeToIdleSeconds、timeToLiveSeconds 判断
    overflowToDisk设定当内存缓存溢出的时候是否将过期的element 缓存到磁盘上
    timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超 过timeToIdleSeconds的属性取值时, 这些数据便 会删除,默认值是0,也就是可闲置时间无穷大
    timeToLiveSeconds缓存element的有效生命期,默认是0.,也就是 element存活时间无穷大
    diskSpoolBufferSizeMBDiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个Cache都应该有自己的一个缓冲区
    diskPersistent在VM重启的时候是否启用磁盘保存EhCache中的数 据,默认是false。
    diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔,默认是120秒。每 个120s, 相应的线程会进行一次EhCache中数据的 清理工作
    memoryStoreEvictionPolicy当内存缓存达到最大,有新的element加入的时 候, 移除缓存中element的策略。 默认是LRU(最 近最少使用),可选的有LFU(最不常使用)和 FIFO(先进先出)

    10. MyBatis逆向工程

    • 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
    • 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
      • Java实体类
      • Mapper接口
      • Mapper映射文件

    10.1 创建逆向工程

    创建逆向工程的步骤:

    1. 引入相关依赖
    2. 创建mybatis-核心配置文件
    3. 创建逆向工程相关配置文件
    4. 执行MBG逆向工程插件

    10.1.1 引入逆向工程所需依赖

    <!-- 依赖MyBatis核心包 -->
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
    </dependencies>
    
    <!-- 控制Maven在构建过程中相关配置 -->
    <build>
    	<plugins>
    	    <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
    	    <plugin>
    	        <groupId>org.mybatis.generator</groupId>
    	        <artifactId>mybatis-generator-maven-plugin</artifactId>
    	        <version>1.3.0</version>
    	        <!-- 插件的依赖 -->
    	        <dependencies>
    	            <!-- 逆向工程的核心依赖 -->
    	            <dependency>
    	                <groupId>org.mybatis.generator</groupId>
    	                <artifactId>mybatis-generator-core</artifactId>
    	                <version>1.3.2</version>
    	            </dependency>
    	            <!-- 数据库连接池 -->
    	            <dependency>
    	                <groupId>com.mchange</groupId>
    	                <artifactId>c3p0</artifactId>
    	                <version>0.9.2</version>
    	            </dependency>
    	            <!-- MySQL驱动 -->
    	            <dependency>
    	                <groupId>mysql</groupId>
    	                <artifactId>mysql-connector-java</artifactId>
    	                <version>5.1.8</version>
    	            </dependency>
    	        </dependencies>
    	    </plugin>
    	</plugins>
    </build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    10.1.2 创建MyBatis核心配置文件

    <?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">
    <configuration>
        <!--自定义properties配置文件的位置-->
        <properties resource=""/> 
        <settings>
            <!--弃用驼峰命名转换-->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <typeAliases></typeAliases>
    
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
    
        <mappers>
            <package name=""/>
        </mappers>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    10.1.3 创建逆向工程的配置文件

    注意:文件名必须是:generatorConfig.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
        <!--
        targetRuntime: 执行生成的逆向工程的版本
            MyBatis3Simple: 生成基本的CRUD(简洁版)
            MyBatis3: 生成带条件的CRUD(高级版)
        -->
        <context id="DB2Tables" targetRuntime="MyBatis3Simple">
            <!-- 数据库的连接信息 -->
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/mybatis"
                            userId="root"
                            password="123456">
            </jdbcConnection>
            <!-- javaBean的生成策略-->
            <javaModelGenerator targetPackage="com.jc.mybatis.pojo"
                                targetProject=".\src\main\java">
                <!--将enableSubPackages设置为true就是使用“ . ” 分割的是文件夹,而不是文件名-->
                <property name="enableSubPackages" value="true"/>
                <!--去掉首尾字符串-->
                <property name="trimStrings" value="true"/>
            </javaModelGenerator>
            <!-- SQL映射文件的生成策略 -->
            <sqlMapGenerator targetPackage="com.jc.mybatis.mapper"
                             targetProject=".\src\main\resources">
                <property name="enableSubPackages" value="true"/>
            </sqlMapGenerator>
            <!-- Mapper接口的生成策略 -->
            <javaClientGenerator type="XMLMAPPER"
                                 targetPackage="com.jc.mybatis.mapper" targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true"/>
            </javaClientGenerator>
            <!-- 逆向分析的表 -->
            <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
            <!-- domainObjectName属性指定生成出来的实体类的类名 -->
            <table tableName="t_emp" domainObjectName="Emp"/>
            <table tableName="t_dept" domainObjectName="Dept"/>
        </context>
    </generatorConfiguration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    10.1.4 执行逆向工程

    如果依赖导入成功,在mavne栏会有这个个插件,双击运行即可生成所配置的实体类,Mapper接口和Mapper文件。

    注意:根据配置的不同,可以生成MyBatis3Simple版和MyBatis3版(可以使用QBC查询)。

    在这里插入图片描述

    执行逆向工程后生成的结果如下:

    MyBatis3Simple 简洁版:

    在这里插入图片描述

    MyBatis3(高级版):

    相较与simple版的多了XxxExample类,通过Example可以帮助我们实现QBC查询。

    在这里插入图片描述

    10.2 QBC查询

    QBC即Quary By Criteria,Criteria是Criterion的复数,译为规则,准则,在sql语句中相当于查询条件。QBC查询是将查询条件通过Java对象进行模块化封装。

    需要使用逆向工程生成的Example对象来实现。

    使用举例:

    @Test
    public void testQBC() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        
        // 创建对应的Example对象
        EmpExample example = new EmpExample();
    
        // 相当于拼接sql语句的条件
        example.createCriteria().andAgeBetween(20, 30).andDidIsNotNull();
        // 相当于sql中的or关键字拼接
        example.or().andEmpNameEqualTo("a1");
        List<Emp> emps = mapper.selectByExample(example);
        emps.forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    打印结果:

    2022-06-24 13:04:07 DEBUG selectByExample:137 - ==>  Preparing: select eid, emp_name, age, sex, email, did from t_emp WHERE ( age between ? and ? and did is not null ) or( emp_name = ? )
    2022-06-24 13:04:07 DEBUG selectByExample:137 - ==> Parameters: 20(Integer), 30(Integer), a1(String)
    2022-06-24 13:04:07 DEBUG selectByExample:137 - <==      Total: 4
    Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', did=3}
    Emp{eid=2, empName='李四', age=22, sex='女', email='123@qq.com', did=1}
    Emp{eid=4, empName='赵六', age=25, sex='男', email='123@qq.com', did=2}
    Emp{eid=9, empName='a1', age=20, sex='男', email='123456789@qq.com', did=null}	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以执行的sql语句是:

    select eid, emp_name, age, sex, email, did from t_emp WHERE ( age between ? and ? and did is not null ) or( emp_name = ? )
    
    • 1

    11. MyBatis的分页插件

    添加依赖:

    从依赖就可以看出,分页插件是一个拦截器

    <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.2.0</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在主配置文件中开启插件:

    <plugins>
    	<!--设置分页插件-->
    	<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
    • 1
    • 2
    • 3
    • 4

    11.1 简单使用

    @Test
    public void testPagehelper1() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    
        // 返回的对象是查询后的分页对象
        // 必须执行在查询前,并且一定要执行查询功能。
        Page<Emp> page = PageHelper.startPage(1, 5);
        List<Emp> emps = mapper.selectByExample(null);
        System.out.println("当前页码: " + page.getPageNum());
        System.out.println("总页数: " + page.getPages());
        System.out.println("每页数量: " + page.getPageSize());
        System.out.println("总记录数: " + page.getTotal());
        System.out.println("当前页的第一条数据的索引: " + page.getStartRow());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    11.2 更加高级的使用

    @Test
    public void testPagehelper2() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    
        // 返回的对象是查询后的分页对象
        // 必须执行在查询前,并且一定要执行查询功能。
        Page<Emp> page = PageHelper.startPage(1, 5);
    
        mapper.selectByExample(null);
    
        PageInfo<Emp> pageInfo = new PageInfo<>(page);
        System.out.println(pageInfo.isIsFirstPage());      //是否是第一页
        System.out.println(pageInfo.isHasNextPage());      //是否有下一页
        System.out.println(pageInfo.getNextPage());        //获取下一页的页码
        System.out.println(pageInfo.isHasPreviousPage());  //是否有上一页
        System.out.println(pageInfo.getPageNum());         //获取当前页码数
        System.out.println(pageInfo.getTotal());           //获取总记录数
        System.out.println(pageInfo.getPages());           //获取总页数
        System.out.println(pageInfo.getPageSize());        //获取一页的记录
        System.out.println(pageInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    【CesiumJS-5】绘制动态路线实现飞行航线、汽车轨迹、路径漫游等
    Vue太难啦!从入门到放弃day02——vue常用特性
    10款Visual Studio实用插件
    mysql同一个数据值,获取最新的一条数据
    JavaScript面试题6
    一家公司做了两年软件测试,只会功能测试,现在已经感到危机感了,那如何摆脱困境呢?
    Docker超详细基础教程
    万字长文Python面试题
    document.getElementById()报错处理
    51、图论-岛屿数量
  • 原文地址:https://blog.csdn.net/qq_51628741/article/details/125448295