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. 初始准备

  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;
    }
    
}

2. 引入相关 jar

<dependencies>
    <!--测试类使用-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    
    <!--MyBatis jar-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>
    
    <!--MySQL8 jar-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    
    <!--LomBok jar-->
    <!--可用注解代替 Alt + Insert 自动生成getter/setter-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>

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
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

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

可去官网 v 一份过来,咳咳
官网链接 => 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 核心配置文件-->
<configuration>
    <!--MyBatis核心配置文件中,标签的顺序:
    properties?,settings?,typeAliases?,typeHandlers?,
    objectFactory?,objectWrapperFactory?,reflectorFactory?,
    plugins?,environments?,databaseIdProvider?,mappers? -->
    
    <!--引入外部配置文件-->
    <properties resource="Db.properties"/>

    <settings>
        <!--数据库的 '_' 默认对应 Java 中的驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--别名的使用-->
    <typeAliases>

        <!--1.typeAlias-->
        <typeAlias type="com.nuo.pojo.User" alias="user"/>

        <!--2.package => 适用于 JavaBean ,会使用 Bean 的首字母小写的非限定类名来作为它的别名-->
        <!--com.nuo.pojo.User => user-->
        <!--<package name="com.nuo.pojo"/>-->

        <!--3.使用注解-->
        <!--  @Alias("user")  可覆盖 package 的默认别名-->
    </typeAliases>


    <!--default:默认环境-->
    <environments default="development">

        <environment id="development">

            <!--事务管理器-->
            <!--在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):-->
            <!--JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。-->
            <!--MANAGED – 被管理, 例如Spring-->
            <transactionManager type="JDBC"/>

            <!--数据源-->
            <!--有三种内建的数据源类型(type="[ POOLED | UNPOOLED | JNDI ]")-->
            <!--POOLED  : 表示使用数据库连接池缓存数据库连接-->
            <!--UNPOOLED: 表示不使用数据库连接池-->
            <!--JNDI    : 表示使用上下文中的数据源-->
            <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>

    <!--映射器-->
    <!--每一个 ...Mapper.xml 都要在 mybatis 核心文件中进行配置-->
    <mappers>

        <!-- 1.使用相对于类路径的资源引用 eg.-->
        <mapper resource="com/nuo/dao/UserMapper.xml"/>
        <!--<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>-->

        <!--2.使用完全限定资源定位符(URL)eg.-->
        <!--<mapper url="file:///var/mappers/AuthorMapper.xml"/>-->

        <!--3.使用映射器接口实现类的完全限定类名 eg.-->
        <!--要求 :-->
        <!--1. 接口 和 .xml 必须同名-->
        <!--2. 接口 和 .xml 必须在同一个包下-->
        <!--<mapper class="org.mybatis.builder.AuthorMapper"/>-->
        <!--<mapper class="com.nuo.dao.UserMapperTest"/>-->

        <!--4.将包内的映射器接口实现全部注册为映射器 eg.-->
        <!--要求 :-->
        <!--1. 接口 和 .xml 必须同名-->
        <!--2. 接口 和 .xml 必须在同一个包下-->
        <!--<package name="org.mybatis.builder"/>-->
    </mappers>

</configuration>

5. 创建 mapper 接口

UserMapper.java

public interface UserMapper {
    // 添加一个 user
    int addUser();
}

6. 创建MyBatis的映射文件

UserMapper.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 -> 绑定一个 Dao/Mapper 接口-->
<mapper namespace="com.nuo.dao.UserMapper">
    <insert id="addUser">
        insert into user (id, name, pwd)
        values (1, 'nuo', '123456');
    </insert>
</mapper>

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();
    }

}

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.关闭资源

9. 加入log4j日志功能

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

  1. jar
<dependencies>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>
  1. log4j 的配置文件 => log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!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>

CRUD

<insert></insert>
<delete></delete>
<update></update>
<select></select>
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<String, Object> 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<Map<String, Object>> 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 动态设置表名需要使用${},而不能使用#{}
    // 因为 ${} => 不带''  #{} => 含''
}
<?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 -> 绑定一个 Dao/Mapper 接口-->
<mapper namespace="com.nuo.dao.UserMapper">

    <!--无法赋值给pojo-->
    <!--<insert id="addUser" parameterType="com.nuo.pojo.User">-->
    <!--    insert into user (id, name, pwd)-->
    <!--    values (#{id}, #{name}, #{pwd});-->
    <!--</insert>-->

    <!--可以获取到自动递增的主键-->
    <!--useGeneratedKeys:设置当前标签中的 sql 使用了自增主键-->
    <!--keyProperty:将自增的主键的值赋给传输的映射文件中参数的某个属性,可以同时赋值给pojo-->
    <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>
    <!--按照 id 批量删除 user-->
    <!--int deleteUsers(@Param("ids") String ids);-->
    <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>


    <!--'$'会出现 sql 注入 => ${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中,可能引发sql注入-->

    <!--'#'不会 => #{}是预编译处理,MyBatis在处理#{}时,它会将sql中的#{}替换为'?',然后调用-->
    <!--PreparedStatement的set方法来赋值,传入字符串后,会在值两边加上单引号,使用占位符的方式提高效率,可以防止sql注入。-->

    <select id="getUserListByLike" parameterType="String" resultType="com.nuo.pojo.User">
    <!--select * 
        from user u 
        where u.name like '%${value}%'
    -->    
    <!--select * 
        from user u
        where u.name like "%"#{value}"%"
     -->
        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="getUserList" resultType="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. 查询的标签select必须设置属性 `resultType` 或 `resultMap`,用于设置实体类和数据库表的映射关系
	1. resultType:自动映射,用于属性名和表中字段名一致的情况
	2. resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况

2. 常见的使用${}的情况:
	1.当sql中表名是从参数中取的情况
	2.批量删除的 where id in (ids)
	3.order by排序语句中, 因为order by 后边必须跟字段名,这个字段名不能带引号,如果带引号会被识别会字符串,而不是字段。

自定义映射

0. demo

查询

1)一对多
    集合 => collection
2)多对一
    对象 => association
  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. 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. 按照查询嵌套处理

    思路

        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>

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>

javaType & ofType
	javaType => pojo 中的属性类型
	ofType   => pojo 实体类 (泛型)

动态 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

2. 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">
            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>

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>

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>

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. 一级缓存

生命周期 : 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) 不同的SqlSession对应不同的一级缓存
    2) 同一个SqlSession但是查询条件不同
    3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
    4) 同一个SqlSession两次查询期间手动清空了缓存

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)没有开启二级缓存,查询时也不会在二级缓存中查询。

3. 查询顺序

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

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

4. 自定义缓存

EhCache
    一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布
式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet
过滤器,支持REST和SOAP api等特点。

使用步骤
    1.导包
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.1</version>
        </dependency>
    2.配置
         <cache type="org.mybatis.caches.ehcache.EhcacheCache(五种可选)"/>
    3.创建 .xml 配置文件(可自定义)

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

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<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. mybatis用于生成代码的配置文件 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="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=GMT%2B8"
                        userId="root"
                        password="xiaonuo123..">
            <!--8.0须设置 , 否则 MySQL 内置表的字段也会出现在生成的代码中-->
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.nuo.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.nuo.mapper"  targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.nuo.mapper"  targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="user" domainObjectName="User"/>
        <!--<table tableName="t_dept" domainObjectName="Dept"/>-->
    </context>
</generatorConfiguration>

2. pom.xml 中配置生成器

<!-- 控制Maven在构建过程中相关配置 -->
<build>
    <!-- 构建过程中用到的插件 -->
    <plugins>
        <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>
            <configuration>
                <!-- 加载mybatis用于生成代码的配置文件,这个文件要在这个路径下 -->
                <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                <verbose>true</verbose>
                <overwrite>true</overwrite>
            </configuration>
            <!-- 插件的依赖 -->
            <dependencies>
                <!-- 逆向工程的核心依赖 -->
                <dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
                </dependency>
                <!-- MySQL驱动 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.27</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

分页插件

1. jar

<dependency> 
    <groupId>com.github.pagehelper</groupId>     
    <artifactId>pagehelper</artifactId> 
    <version>5.2.0</version> 
</dependency>

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

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

3. 相关参数

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

4. 相关返回数据

pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值