• Mybatis


    MyBatis 简介

    1. MyBatis历史

    MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。
    iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。

    2. 特性 => 半自动化持久层框架

    1. MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
    2. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
    3. MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old JavaObjects,普通的Java对象)映射成数据库中的记录
    4. MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架

    3. 其它持久化层技术

    JDBC
    	1. SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
    	2. 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    	3. 代码冗长,开发效率低
    
    Hibernate 和 JPA (全自动框架)
    	1. 操作简便,开发效率高
    	2. 程序中的长难复杂 SQL 需要绕过框架
    	3. 内部自动生产的 SQL,不容易做特殊优化
    	4. 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
    	5. 反射操作太多,导致数据库性能下降
    
    MyBatis
    	1. 轻量级,性能出色
    	2. SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    	3. 开发效率稍逊于HIbernate,但是完全能够接受
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    框架搭建

    1. 初始准备

    1. MySQL
      user.sql

    2. pojo -> User.java

    package com.nuo.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    /**
     * @author nuo
     * @version 1.0
     * @description: TODO
     * @date 2022/2/14 20:01
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {
    
        private int id;
        private String name;
        private String pwd;
    
        public User(String name, String pwd) {
            this.name = name;
            this.pwd = pwd;
        }
        
    }
    
    • 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

    2. 引入相关 jar

    <dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
            <scope>testscope>
        dependency>
        
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.10version>
        dependency>
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.29version>
        dependency>
        
        
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.24version>
        dependency>
    dependencies>
    
    • 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

    3. 创建数据库的配置文件 Db.properties

    MySQL 不同版本的注意事项
    1. 驱动类driver-class-name
    	MySQL 5版本使用jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver
    	MySQL 8版本使用jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver
    2. 连接地址url
    	MySQL 5版本的url:
    		jdbc:mysql://localhost:3306/mybatis
    	MySQL 8版本的url:
    		jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
    	否则运行测试用例报告如下错误:
    		java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
    username=root
    password=123456
    
    • 1
    • 2
    • 3
    • 4

    4. 创建MyBatis的核心配置文件 mybatis-config.xml

    可去官网 v 一份过来,咳咳
    官网链接 => MyBatis

    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
        
        
        
        <properties resource="Db.properties"/>
    
        <settings>
            
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        settings>
    
        
        <typeAliases>
    
            
            <typeAlias type="com.nuo.pojo.User" alias="user"/>
    
            
            
            
    
            
            
        typeAliases>
    
    
        
        <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>
    
            <environment id="test">
                <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="com/nuo/dao/UserMapper.xml"/>
            
    
            
            
    
            
            
            
            
            
            
    
            
            
            
            
            
        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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    5. 创建 mapper 接口

    UserMapper.java

    public interface UserMapper {
        // 添加一个 user
        int addUser();
    }
    
    • 1
    • 2
    • 3
    • 4

    6. 创建MyBatis的映射文件

    UserMapper.xml

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.nuo.dao.UserMapper">
        <insert id="addUser">
            insert into user (id, name, pwd)
            values (1, 'nuo', '123456');
        insert>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7. 通过junit测试

    public class UserMapperTest {
        @Test
        public void addUser() throws IOException {
            //读取MyBatis的核心配置文件 
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); 
            //创建SqlSessionFactoryBuilder对象 
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); 
            //通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象 
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); 
            //创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务 
            //SqlSession sqlSession = sqlSessionFactory.openSession(); 
            //创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
    
            // int res = sqlSession.insert("com.nuo.dao.UserMapper.addUser") 不推荐
            
            //通过代理模式创建UserMapper接口的代理实现类对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
            int res = userMapper.addUser();
    
            if (res > 0) {
                System.out.println("添加成功");
            } else {
                System.out.println("添加失败");
            }
            sqlSession.close();
        }
    
    }
    
    • 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

    8. Mybatis 执行流程

    1.Resource 获取配置文件输入流
    2.实例化 SqlSessionFactoryBuilder
    3.build(inputStream) (解析配置文件) -> SqlSessionFactory
    4.transactional 事务管理器
    5.创建 executor 执行器
    6.sqlSessionFactory.openSession() 获取 sqlSession
    7.实现 CRUD (可能回滚事务 ------> 4)
    8.查看是否执行成功 (失败 回滚事务 ------> 4)
    9.提交事务
    10.关闭资源
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    9. 加入log4j日志功能

    日志的级别:
    FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

    1. jar
    <dependencies>
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. log4j 的配置文件 => log4j.xml
    
    DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
        <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
            <param name="Encoding" value="UTF-8" />
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
            layout>
        appender>
        <logger name="java.sql">
            <level value="debug" />
        logger>
        <logger name="org.apache.ibatis">
            <level value="info" />
        logger>
        <root>
            <level value="debug" />
            <appender-ref ref="STDOUT" />
        root>
    log4j:configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    CRUD

    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    package com.nuo.dao;
    
    import com.nuo.pojo.User;
    import org.apache.ibatis.annotations.MapKey;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    import java.util.Map;
    
    public interface UserMapper {
    
        // 添加一个 user
        int addUser(User user);
    
        // 删除一个用户
        int deleteUser(User user);
    
        // 按照 id 批量删除 user
        int deleteUsers(@Param("ids") String ids);
    
        // 修改用户
        int updateUser(User user);
    
        // 根据 id 查询 用户
        User getUserById(int id);
    
        // 模糊查询
        List<User> getUserListByLike(String value);
    
        // 获取全部用户
        List<User> getUserList();
    
        // 测试使用 map
        int addUserTestMap(Map<String, Object> map);
    
        // 单条查询结果用 map 接收  k->v   字段->值
        // {name=诺, id=1, pwd=123456}
        //Map getUserByIdToMap(@Param("id") int id);
    
        // 单条查询结果用 map 接收  k->v   对应字段的值->所有字段键值对
        // {1={name=诺, id=1, pwd=123456}}
        @MapKey("id")
        Map<String, Object> getUserByIdToMap(@Param("id") int id);
    
        // 多条查询结果用 map 接收
        // [{name=诺, id=1, pwd=123456}, {name=nuo, id=2, pwd=123123}, {name=aaa, id=3, pwd=123123}, {name=test, id=5, pwd=aaaaaaa}, {name=nnnnn, id=6, pwd=123123}]
        // List> getUserListToMap();
    
        // {1={name=诺, id=1, pwd=123456}, 2={name=nuo, id=2, pwd=123123}, 3={name=aaa, id=3, pwd=123123}, 5={name=test, id=5, pwd=aaaaaaa}, 6={name=nnnnn, id=6, pwd=123123}}
        @MapKey("id")
        Map<String, Object> getUserListToMap();
    
    
        // MyBatis 动态设置表名需要使用${},而不能使用#{}
        // 因为 ${} => 不带''  #{} => 含''
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    
    <mapper namespace="com.nuo.dao.UserMapper">
    
        
        
        
        
        
    
        
        
        
        <insert id="addUser" useGeneratedKeys="true" keyProperty="id" parameterType="com.nuo.pojo.User">
            insert into user (id, name, pwd)
            values (null, #{name}, #{pwd});
        insert>
    
        <insert id="addUserTestMap" parameterType="map">
            insert into user (id, name, pwd)
            values (#{userId}, #{userName}, #{userPwd});
        insert>
    
        <delete id="deleteUser" parameterType="com.nuo.pojo.User">
            delete
            from user
            where id = #{id};
        delete>
        
        
        <delete id="deleteUsers">
            delete
            from user
            where id in (${ids});
        delete>
    
        <update id="updateUser" parameterType="com.nuo.pojo.User">
            update user
            set name=#{name},
            pwd=#{pwd}
            where id = #{id};
        update>
    
    
        <select id="getUserById" parameterType="int" resultType="com.nuo.pojo.User">
            select *
            from user
            where id = #{id};
        select>
    
    
        
    
        
        
    
        <select id="getUserListByLike" parameterType="String" resultType="com.nuo.pojo.User">
            
        
            select *
            from user u
            where u.name like concat('%', #{value}, '%');
        select>
    
    
        <select id="getUserList" resultType="com.nuo.pojo.User">
            select *
            from user;
        select>
    
        
        
        
        
        
    
        <select id="getUserByIdToMap" resultType="map">
            select *
            from user u
            where u.id = #{id};
        select>
    
    
        <select id="getUserListToMap" resultType="map">
            select *
            from user;
        select>
    
    mapper>
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    注意:

    1. 查询的标签select必须设置属性 `resultType` 或 `resultMap`,用于设置实体类和数据库表的映射关系
    	1. resultType:自动映射,用于属性名和表中字段名一致的情况
    	2. resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
    
    2. 常见的使用${}的情况:
    	1.当sql中表名是从参数中取的情况
    	2.批量删除的 where id in (ids)
    	3.order by排序语句中, 因为order by 后边必须跟字段名,这个字段名不能带引号,如果带引号会被识别会字符串,而不是字段。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自定义映射

    0. demo

    查询

    1)一对多
        集合 => collection
    2)多对一
        对象 => association
    
    • 1
    • 2
    • 3
    • 4
    1. Student
    package com.nuo.pojo;
    
    import lombok.Data;
    import org.apache.ibatis.type.Alias;
    
    @Data
    public class Student {
        private int id;
        private String name;
        
        private Teacher teacher;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. Teacher
    package com.nuo.pojo;
    
    import lombok.Data;
    import org.apache.ibatis.type.Alias;
    
    import java.util.List;
    
    @Data
    public class Teacher {
        private int id;
        private String name;
        
        private List<Student> students;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1. 按照查询嵌套处理

        思路
    
            1.查询获取所有学生信息
            2.根据查询出来学生的 tid ,寻找对应的老师 => 子查询
            <select id="getStudentList1" resultMap="StudentMap1">
                select *
                from student;
            </select>
    
            <resultMap id="StudentMap1" type="student">
                <result property="id" column="id"/>
                <result property="name" column="name"/>
                <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
            </resultMap>
    
            <select id="getTeacher" resultType="teacher">
                select *
                from teacher
                where id = #{id};
            </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2. 按照结果嵌套处理

    思路
        多表查询
    
    • 1
    • 2
            <select id="getStudentList2" resultMap="StudentMap2">
                select s.id sid,s.name sname,s.tid,t.name tname
                from student s,teacher t
                where s.tid = t.id;
            select>
    
            <resultMap id="StudentMap2" type="student">
                <result property="id" column="sid"/>
                <result property="name" column="sname"/>
                <association property="teacher" javaType="teacher">
                    <result property="id" column="tid"/>
                    <result property="name" column="tname"/>
                association>
            resultMap>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    javaType & ofType
    	javaType => pojo 中的属性类型
    	ofType   => pojo 实体类 (泛型)
    
    • 1
    • 2
    • 3

    动态 SQL

    1. if 的使用

        <select id="queryBlogIf" parameterType="map" resultType="blog">
            select *
            from blog b
            <where>
                <if test="title != null">
                    title like concat('%',#{title},'%')
                </if>
                <if test="author != null">
                    and author like concat('%',#{author},'%')
                </if>
            </where>
        </select>
        
    【PS】:
       1. 若 where 标签中的 if 条件都不满足,则where标签没有任何功能, 即不会添加 where 关键字
       2. 若 where 标签中的 if 条件满足,则 where 标签会自动添加 where 关键字,并将条件最前方多余的 and 去掉
    注意:where 标签不能去掉条件最后多余的 and
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2. trim

    trim 用于去掉或添加标签中的内容

    常用属性:
        prefix         :在 trim 标签中的内容的前面添加某些内容
        prefixOverrides:在 trim 标签中的内容的前面去掉某些内容
        suffix         :在 trim 标签中的内容的后面添加某些内容
        suffixOverrides:在 trim 标签中的内容的后面去掉某些内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    <select id="getEmpListByMoreTJ" resultType="Emp"> 
        select * from t_emp 
        <trim prefix="where" suffixOverrides="and"> 
            <if test="ename != '' and ename != null">
                ename = #{ename} 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

    3. choose(when,otherwise)

        类似 Java 中的 switch
        <select id="queryBlogChoose" parameterType="map" resultType="blog">
            select *
            from blog b where
            <choose>
                <when test="title != null">
                    title like concat('%',#{title},'%')
                </when>
                <when test="author != null">
                    author like concat('%',#{author},'%')
                </when>
                <otherwise>
                    1 = 1
                </otherwise>
            </choose>
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4. foreach (集合遍历) 【通常在构建 in 条件语句的时候使用】

        <select id="selectPostIn" resultType="domain.blog.Post">
            SELECT *
            FROM POST P
            <where>
                <foreach item="item" index="index" collection="list"
                    open="ID in (" separator="," close=")" nullable="true">
                    #{item}
                </foreach>
            </where>
        </select>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4. sql片段 (代码复用)

        类似方法调用
            => 1.最好基于单表来定义 sql 片段
            => 2.不要存在 where 标签
        <sql id="if-title-author">
            <if test="title != null">
                title like concat('%',#{title},'%')
            </if>
            <if test="author != null">
                and author like concat('%',#{author},'%')
            </if>
        </sql>
    
        <select id="queryBlogIf" parameterType="map" resultType="blog">
            select *
            from blog b
            <where>
                <include refid="if-title-author"/>
            </where>
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    缓存

    1. 一级缓存

    生命周期 : SqlSession
    	0.关于 SqlSession
    		每个线程都应该有它自己的 SqlSession 实例
        SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession
    实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比
    如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域
    中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次
    都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
    
    	1.如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中
    的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
    
    	2.当一个SqlSession结束后那么他里面的一级缓存也就不存在了,mybatis默认是开启一级缓存,不需要配置
    	3.可手动清空缓存
           sqlSession.clearCache();
    
    	4.mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的,意思就是,SqlSessionHashMap存储缓存数据时,是使
    用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。
        eg.-1242243203:1146242777:winclpt.bean.userMapper.getUser:0:2147483647:select * from user where id=?:19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    使一级缓存失效的四种情况:
        1) 不同的SqlSession对应不同的一级缓存
        2) 同一个SqlSession但是查询条件不同
        3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
        4) 同一个SqlSession两次查询期间手动清空了缓存
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 二级缓存 (全局缓存) => 基于 namespace

    生命周期 : SqlSessionFactory
        1) 步骤 :
    
            1.mybatis-config.xml 中显示的开启全局缓存 (虽然它默认是开启的,显示开启可提高可读性)
    
                <settings>
                    <setting name="cacheEnabled" value="true"/>
                </settings>
    
            2....Mapper.xml 中配置 '<cache/>'
    
                eg. <mapper namespace="com.nuo.dao.UserMapper">
                        <cache/>
                        <select>...</select>
                    </mapper>
    
                <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"/>
                        缓存的收回策略      刷新间隔 (ms)         是否只读        引用数目
                  默认      LRU               不清空              false           1024
    
                eviction :缓存的收回策略
                    LRU (最近最少使用的) 移除最长时间不被使用的对象,这是默认值
                    FIFO (先进先出) 按对象进入缓存的顺序来移除它们
                    SOFT (软引用) 移除基于垃圾回收器状态和软引用规则的对象
                    WEAK (弱引用) 更积极地移除基于垃圾收集器状态和弱引用规则的对象
    
                readOnly:是否只读
                    true:只读,设置为true后,mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据,因此为了加快获取速度, 一般会直接将数据在缓存中的引用交给用户,虽然速度快,但不安全。
                    false:非只读,设置为false后,mybatis认为获取的数据可能会被修改,因此会利用序列化和反序列化的技术克隆一份新的数据给你,虽然速度慢,但安全。
    
            3.给 POJO 类实现序列化接口
    
                public class User implements Serializable {...}
    
        2)在开启二级缓存时,查出来的数据默认先存储在一级缓存中,当有 SqlSession关闭 时,它里面一级缓存中的数据就会被存
    储到 Mapper 的二级缓存中,这样该Mapper中的其他会话执行了相同方法时,就会在二级缓存中找到匹配的数据,如果没有找到,才
    会去数据库中查找。注意只有在该会话关闭时,它一级缓存中的数据才会被刷到二级缓存中。另外如果只是开启二级缓存的全局(config)
    开关,而会话(student)没有开启二级缓存,查询时也不会在二级缓存中查询。
    
    • 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

    3. 查询顺序

    二级缓存 ----> 一级缓存 ----> 数据库

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

    4. 自定义缓存

    EhCache
        一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布
    式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet
    过滤器,支持REST和SOAP api等特点。
    
    使用步骤
        1.导包
            
                org.mybatis.caches
                mybatis-ehcache
                1.2.1
            
        2.配置
             
        3.创建 .xml 配置文件(可自定义)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    配置说明 :
    在这里插入图片描述

    ehcache.xml

    
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
    
        <diskStore path="./tmpdir/Tmp_EhCache"/>
    
        <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="259200"
                memoryStoreEvictionPolicy="LRU"/>
    
        <cache
                name="cloud_user"
                eternal="false"
                maxElementsInMemory="5000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="1800"
                memoryStoreEvictionPolicy="LRU"/>
    ehcache>
    
    • 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

    逆向工程

    1. mybatis用于生成代码的配置文件 generatorConfig.xml

    
    DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
        
        <context id="DB2Tables" targetRuntime="MyBatis3">
            
            <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8"
                            userId="root"
                            password="xiaonuo123..">
                
                <property name="nullCatalogMeansCurrent" value="true"/>
            jdbcConnection>
            
            <javaModelGenerator targetPackage="com.nuo.pojo" targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            javaModelGenerator>
            
            <sqlMapGenerator targetPackage="com.nuo.mapper"  targetProject=".\src\main\resources">
                <property name="enableSubPackages" value="true" />
            sqlMapGenerator>
            
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.nuo.mapper"  targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
            javaClientGenerator>
            
            
            
            <table tableName="user" domainObjectName="User"/>
            
        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

    2. pom.xml 中配置生成器

    
    <build>
        
        <plugins>
            
            <plugin>
                <groupId>org.mybatis.generatorgroupId>
                <artifactId>mybatis-generator-maven-pluginartifactId>
                <version>1.3.0version>
                <configuration>
                    
                    <configurationFile>src/main/resources/generatorConfig.xmlconfigurationFile>
                    <verbose>trueverbose>
                    <overwrite>trueoverwrite>
                configuration>
                
                <dependencies>
                    
                    <dependency>
                        <groupId>org.mybatis.generatorgroupId>
                        <artifactId>mybatis-generator-coreartifactId>
                        <version>1.3.2version>
                    dependency>
                    
                    <dependency>
                        <groupId>mysqlgroupId>
                        <artifactId>mysql-connector-javaartifactId>
                        <version>8.0.27version>
                    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

    分页插件

    1. jar

    <dependency> 
        <groupId>com.github.pagehelpergroupId>     
        <artifactId>pagehelperartifactId> 
        <version>5.2.0version> 
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. mybatis-config.xml 中配置插件

    <plugins> 
         
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>
    
    • 1
    • 2
    • 3
    • 4

    3. 相关参数

    pageSize:每页显示的条数
    pageNum:当前页的页码
    index:当前页的起始索引,index=(pageNum-1)*pageSize
    count:总记录数
    totalPage:总页数
    totalPage = count / pageSize;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4. 相关返回数据

    pageNum:当前页的页码
    pageSize:每页显示的条数
    size:当前页显示的真实条数
    total:总记录数
    pages:总页数
    prePage:上一页的页码
    nextPage:下一页的页码
    isFirstPage/isLastPage:是否为第一页/最后一页
    hasPreviousPage/hasNextPage:是否存在上一页/下一页
    navigatePages:导航分页的页码数
    navigatepageNums:导航分页的页码,[1,2,3,4,5]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    k8s-身份认证与权限
    图像处理中常见的几种插值方法:最近邻插值、双线性插值、双三次插值(附Pytorch测试代码)
    多节点单进程
    IP地址定位基础数据采集
    Linux权限总结
    如何定位线上CPU占用过高的问题
    iOS——Manager封装网络请求
    18-Linux系统服务
    【javascript】按下回车键登陆实现
    【HTML】HTML网页设计---海贼王动漫网页设计
  • 原文地址:https://blog.csdn.net/qq_60717329/article/details/126076509