Bootstrap

mybatis框架

一、mybatis基础知识和使用

1.什么是mybatis框架

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

持久层:与数据库交互的一层。-- 用于操作数据表记录的

框架:别人写好的一个半成品。-- 我们需要加入自己的配置以及代码

ORM框架:Object Relative Mapping(对象关系映射)。表--实体类——一条记录实体类的对象。

表的字段--java实体类的属性

2.为什么使用Mybatis

3.如何使用mybatis(步骤)

3.1创建maven的java工程

3.2引入依赖--pom.xml

第一种方式:下载在本地的依赖资源(老师给的maven架包)

第二种方式:mvnrepository.com在线网站搜索选择依赖资源

    <dependencies>
<!--数据库-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>
<!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
<!--unit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
<!-- lombok小辣椒插件:实体类中get、set和toString方法,有/无参构造方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>


<!--引入log4j的jar-&#45;&#45;&#45;&#45;&#45;&#45;必须引入log4j.properties日志属性文件:打印sql语句-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

<!--pageHelper:分页查询的依赖-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>6.1.0</version>
        </dependency>
    </dependencies>

3.3log4j.properties日志属性文件:打印sql语句

log4j.rootLogger=DEBUG, Console

#Console

log4j.appender.Console=org.apache.log4j.ConsoleAppender

log4j.appender.Console.layout=org.apache.log4j.PatternLayout

log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

log4j.logger.java.sql.ResultSet=INFO

log4j.logger.org.apache=INFO

log4j.logger.java.sql.Connection=DEBUG

log4j.logger.java.sql.Statement=DEBUG

log4j.logger.java.sql.PreparedStatement=DEBUG

3.4引入数据源文件--db.properties

企业开发中,习惯把数据源的信息放入属性文件中。在mybatis配置文件中引入该属性文件

#数据源信息

jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai

jdbc.username=root

jdbc.password=root

jdbc.driverClassName=com.mysql.cj.jdbc.Driver

3.5编写配置文件Mybatis.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>
<!-- 引入数据源属性文件-->
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <!--name是固定的 value改为数据源中设置的内容-->
                <property name="driver" value="${jdbc.driverClass}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>

    </environments>

    <!--引入对应的映射文件注意:改为自己的映射文件-->
    <mappers>
        <mapper resource="mapper/RoleMybatis.xml"/>
    </mappers>
</configuration>

3.5.1为实体类起别名

之前我们在映射文件中resultType中返回的实体类类型,全部都是全路径

3.6创建一个实体类

package com.wjy.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @program: mybatis03
 * @description:
 * @author: 王佳瑶
 * @create: 2024-05-20 17:27
 **/
@Data//get、set、toString
// 有/无参构造方法
@NoArgsConstructor
@AllArgsConstructor
public class Role {
    private Integer id;
    private String name;
    private String code;
    private String description;
}

3.7创建一个接口

package com.wjy.dao;

import com.wjy.entity.Role;
import org.apache.ibatis.annotations.Param;

import java.util.List;
//定义实现功能和制定规范
public interface RoleDao {
    public int insert(Role role);//增加--结果影响一行,以stu类提交数据
    public int del(int id);//根据id删除--结果影响一行
    public int update(Role role);//修改--结果影响一行,以stu类提交数据
    public Role selById(int id);//根据id查找数据--返回一个stu类一行的数据
    public List<Role> selAll();//查询所有的信息--返回一个集合容器,泛型为Role类

    //传递多个参数的情况
    //多个参数查询的情况--根据id和姓名查找
    /*如果不使用mybatis为参数起的名称--默认的情况[param1,param2...]
    * 可以使用@Param(" ")的方式
    * 习惯使用@Param为每个参数起名称,在映射文件中#{使用名称}*/
    public Role selByIdAndName(@Param("id") int id,@Param("name") String role_name);
    //--模糊查询
    public List<Role> selByName(String name);//根据姓名查找:返回的是一个集合容器
}


 //其他情况  根据年龄查询-- 会存在特殊符号的情况,使用<![CDATA[sql语句]]>
public List<Stu> selectByAge(@Param("max") int max,@Param("min") int min);

3.8配置映射文件--在resources包下创建一个mapper包

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间
以后需要跟dao接口相同
-->
<mapper namespace="com.wjy.dao.RoleDao">
</mapper>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:命名空间
     以后需要跟dao接口相同
-->
<mapper namespace="com.wjy.dao.RoleDao">
<!--增加    userGeneratedKeys="true":是否使用生成的主键
            keyProperty:生成后的主键赋给哪个属性
  -->
     <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into t_role values (null,#{name},#{code},#{description})
    </insert>
<!--修改-->
    <update id="update">
        update t_role set role_name=#{name},role_code=#{code},description=#{description}  where id=#{id}
    </update>
<!--删除-->
    <delete id="del">
        delete from t_role where id=#{id}
    </delete>


<!--由于数据库中的列名和属性名不一致-->
 <!--第一种起别名的方式-->
    <!--<select id="selById" resultType="com.wjy.entity.Role">
        select id,role_name as name,role_code as code,description from t_role where id=#{id}
    </select>-->
<!--第二种使用ResultMapper属性
    定义映射关系
                id:标识
                type:执行查询后返回的数据类型
                property:类中定义的属性名
                column:数据库中的列名-->
    <resultMap id="myMap" type="com.wjy.entity.Role">
        <id property="id" column="id"/>
        <result property="name" column="role_name"/>
        <result property="code" column="role_code"/>
        <result property="description" column="description"/>
    </resultMap>

<!--查询所有信息-->
    <select id="selAll" resultMap="myMap">
        select * from t_role
    </select>
<!--根据id查找:使用resultMap就不能使用-->
    <select id="selById" resultMap="myMap">
        select * from t_role where id=#{id}
    </select>


<!--根据id和名字查找--多个参数需设置在定义接口时使用@Param("#{}中填写的")注解-->
    <select id="selByIdAndName" resultMap="myMap">
        select * from t_role where id=#{id} and role_name=#{name}
    </select>
<!--模糊查询-->
    <select id="selByName" resultMap="myMap">
        select * from t_role where role_name like concat('%',#{name},'%')
    </select>

<!--根据年龄的范围筛选出对应的数据
            存在特殊字符-处理方式<![CDATA[sql语句]]>
 -->
    <select id="selectByAge" resultMap="myMap">
        <![CDATA[select * from t_student where age > #{min} and age < #{max}]]>
    </select>
</mapper>

3.8.1列名和属性名不一致的情况

查询列无法给对应的属性赋值。

第一种: 查询时为列起别名

让别名与属性名一致

第二种: 使用ResultMapper属性--推荐使用(联表查询时也会用到

3.8.2传递多个参数--接口定义查询时

3.8.3<![CDATA[sql语句]]>--在xml文件中处理特殊符号

使用第二种:<![CDATA[sql语句]]>

3.8.5模糊查询--concat()

3.8.6添加时获取递增的主键值

userGeneratedKeys="true":是否使用生成的主键
keyProperty:生成后的主键赋给哪个属性

3.9单元测试

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wjy.dao.RoleDao;
import com.wjy.entity.Role;
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.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @program: mybatis05
 * @description:
 * @author: 王佳瑶
 * @create: 2024-05-21 08:42
 **/
public class RoleUnit {
    InputStream resourceAsStream =null;
    SqlSessionFactory sessionFactory =null;
    SqlSession sqlSession =null;
    RoleDao roleDao =null;
    //在测试之前加载的注解方法
    @Before
    public void before()throws Exception{
        resourceAsStream=Resources.getResourceAsStream("mybatis.xml");
        sessionFactory=new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession=sessionFactory.openSession();
        roleDao = sqlSession.getMapper(RoleDao.class);
    }
    //增加
    @Test
    public void insert(){
        Role role = new Role(null,"元","student","学生");
        System.out.println("添加前:"+role);
        roleDao.insert(role);
        System.out.println("添加后:"+role);
        sqlSession.commit();
    }

    //修改
    @Test
    public void update(){
        Role role = new Role(13,"佳瑶","student","学生");
        roleDao.update(role);
        sqlSession.commit();
    }
    //删除
    @Test
    public void del(){
        roleDao.del(13);
        sqlSession.commit();
    }
    //根据id查询
    @Test
    public void selById(){
        Role role = roleDao.selById(12);
        System.out.println(role);
    }
    //根据id和姓名查询
    @Test
    public void selByIdAndName(){
        Role role = roleDao.selByIdAndName(12,"王佳瑶");
        System.out.println(role);
    }

    //根据姓名模糊查询
    @Test
    public void selByName(){
        List<Role> roles = roleDao.selByName("w");
        for (Role r:roles) {
            System.out.println(r);
        }
    }
    //查询全部
    @Test
    public void selAll(){
        List<Role> roles = roleDao.selAll();
        for (Role r:roles) {
            System.out.println(r);
        }
    }
    //查询全部--分页版
    @Test
    public void selAllAndLimit(){
        //开启分页功能--起始页1,一页3条数据
        PageHelper.startPage(1,2);
       
        List<Role> roles = roleDao.selAll();//调用自己的方法--会自动在后面给补全分页sql语句
        //把查询到的结果封装到PageInfo类中--包含总条数和当前页的记录
       
        PageInfo<Role> pageInfo = new PageInfo<Role>(roles);
       
        //将来会给前端pageInfo
        System.out.println("总条数:"+pageInfo.getTotal());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("当前页的记录:"+pageInfo.getList());
        sqlSession.commit();
    }
}

4.mybatis的注解(了解)

上面完成crud操作时,通过的都是映射文件来写sql语句完成的。 mybatis也提供了注解模式

5.mybatis分页插件

自己写分页sql. [select * from 表名 where 条件 limit 起始记录,每页显示的条数] [select count(*) from 表名 where 条件] ---使用PageHelper

5.1pageHelper的依赖(前面依赖中有)

<dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper</artifactId>

<version>6.1.0<</version>

</dependency>

5.2引入拦截器--在mybatis配置文件中

写在environments的上方

<plugins>

<!-- com.github.pagehelper为PageHelper类所在包名 -->

<plugin interceptor="com.github.pagehelper.PageInterceptor">

<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->

<property name="param1" value="value1"/>

</plugin>

</plugins>

5.3测试分页查询

6.总结

步骤:

1.创建maven工程

2.在pox.xml中引入依赖(复制查找)

3.在resources资源包下创建数据源文件---1.db.properties关于数据库的连接(复制查找)

2.log4j.properties日志属性文件(复制查找)

4.编写配置Mybatis.xml文件(复制查找)--在这里面有引入资源文件,设置value的值

--最后引入映射文件(mapper包下的关于具体类的操作实现)

5.在entity包下创建对应的实体类--使用注解设置get、set、toString方法等

6.在dao包下创建对应的接口实现类(制定规范)

7.配置对应的映射文件--<!--namespace:命名空间
必须和接口名一致
#{类中的对应的数据中的属性名}-->

<!--增加 userGeneratedKeys="true":是否使用生成的主键
keyProperty:生成后的主键赋给哪个属性
-->

<!--查询 列表和属性要对应
1.使用ResultMap定义映射关系
2.替换查询里的resultType属性
-->

<!--查询所有信息
考虑分页查询的情况:1.引入依赖
2.引入拦截器
3.测试:开启分页PageHelper、把查询到的数据封装到PageInfo中
-->

<!--根据id和姓名-多参-查找
在StuDao中多参传值的时候注解定义了,默认的会有[param1,...]不方便书写
-->

<!--根据年龄的范围筛选出对应的数据
存在特殊字符-处理方式<![CDATA[sql语句]]>
-->

<!--查找名字中有某个字符的所有信息:模糊查询:like 使用concat()方法
-->

7.mybatis实现联表查询

class[cid cname] student(id,name,age, class_id)

回顾: mysql联表的sql语句: select * from student s inner join class c on s.class_id=c.cid

表与表之间的关系: 外键

mybatis中如何封装联表查询的结果。

7.1mybatis完成多对一

从多的一方查询一的一方的信息

1.根据id查询员工的信息及所在部门信息

2.根据部门名查询改部门下的所有员工

7.2mybatis动态sql标签

public List<Emp> selByNameAndJob(@Param("name") String name,@Param("job") String job);//测试if动态sql语句
public List<Emp> selByNameOrJobOrSal(@Param("name") String name,@Param("job") String job);//测试choose when otherwise动态sql语句
public int delById(@Param("id") int[] id);//根据id删除、批量选择性删除
public int insert(@Param("emps") List<Emp> emps);//批量增加
public int update(Emp emp);//根据id修改--set

7.2.1if标签

根据条件查询:1.传递员工名不为null,
按照name条件查询 如果name为null则查询所有
2.传递职位job

<select id="selByNameAndJob" resultMap="myMap">
        select * from emp where 1=1
        <if test="name!=null and name!=''">
            and e_name like concat('%',#{name},'%')
        </if>
        <if test="job!=null and job!=''">
            and JOB like concat('%',#{job},'%')
        </if>
    </select>

7.2.2choose when otherwise标签:

相当于switch或者if else...

<select id="selByNameOrJobOrSal" resultMap="myMap">
        select * from emp where 1=1
        <choose>
            <when test="name!=null and name!=''">
                and E_NAME like concat('%',#{name},'%')
            </when>
            <when test="job!=null and job!=''">
                and JOB =#{job}
            </when>
            <otherwise>
                and SAL > 5000
            </otherwise>
        </choose>
    </select>

7.2.3where

where它可以自动处理条件语句的前缀
当条件满足时自动保证符合sql语法的条件格式
条件都不满足时查询全部内容,也就是where标签之前的完整sql语句
上面测试的都不符合正常规范,这种推荐使用

<select id="selByNameAndJob" resultMap="myMap">
        select * from emp
        <where>
            <if test="name!=null and name!=''">
                and e_name like concat('%',#{name},'%')
            </if>
            <if test="job!=null and job!=''">
                and JOB like concat('%',#{job},'%')
            </if>
        </where>
    </select>

7.2.4foreacch:遍历集合或数组

批量删除/增加等操作:例如:delete from user where id in (1,2,4)
collection: 要遍历的集合元素
item: 遍历时赋予的变量
open: 以。。开头
close: 以。。关闭
separator:分隔符

<delete id="delById">
    delete from emp
    <foreach collection="id" item="id" open="where empno in(" close=")" separator=",">
        #{id}
    </foreach>
 </delete>

<insert id="insert">
    insert into emp values
    <foreach collection="emps" item="e" separator=",">
        (null,#{e.name},#{e.job},#{e.salary},#{e.deptno})
    </foreach>
</insert>

7.2.5set用于修改元素

<update id="update">
        update emp
        <set>
            <if  test="name!=null and name!=''">
                e_name=#{name}
            </if>
            <if test="job!=null and job!=''">
                job=#{job}
            </if>
            <if test="salary!=null and salary!=''">
                sal=#{salary}
            </if>
            <if test="deptno!=null and deptno!=''">
                deptno=#{deptno}
            </if>
        where empno = #{id}
        </set>
    </update>
//if
    @Test
    public void selByNameAndJob(){
        List<Emp> emps = empDao.selByNameAndJob("", "");
        System.out.println(emps);
    }
    //choose when otherwise--只会满足一个条件,相当于case语句中每条都有break,或者if-if else...
    @Test
    public void selByNameOrJobOrSal(){
        List<Emp> emps = empDao.selByNameOrJobOrSal("", "销售经理");
        System.out.println(emps);
    }
    //foreach:批量操作--遍历集合或数组
    @Test
    public void  delById(){
        int [] id = {2,3};
        int i = empDao.delById(id);
        sqlSession.commit();
    }
    @Test
    public void insert(){
        List<Emp> emps = new ArrayList<>();
        emps.add(new Emp(null, "wjy", "boss", 9999,40));
        emps.add(new Emp(null, "gyh", "boss", 9999,40));
        int insert = empDao.insert(emps);
        System.out.println(insert);
        sqlSession.commit();
    }
    //set修改
    @Test
    public void update(){
        Emp emp = new Emp(9,"王佳瑶",null,null,null);
        empDao.update(emp);
        sqlSession.commit();
    }

7.2.6trim标签

它的功能更加强大,它可以替换where和set标签

<!--
      trim:
        prefix:前缀使用set
        suffixOverrides: 后缀覆盖 ,
   -->
    <update id="update">
        update emp
        <trim prefix="set" suffixOverrides=",">
            <if  test="name!=null and name!=''">
                e_name=#{name},
            </if>
            <if test="job!=null and job!=''">
                job=#{job},
            </if>
            <if test="salary!=null and salary!=''">
                sal=#{salary},
            </if>
            <if test="deptno!=null and deptno!=''">
                deptno=#{deptno},
            </if>
        where empno = #{id}
        </trim>
    </update>

    <!--根据条件查询-->
    <select id="selectByCondition01" resultType="com.aaa.entity.User">
        select * from user
        <trim prefix="where" prefixOverrides="and |or">
            <if test="name!=null and name!=''">
                or name like concat('%',#{name},'%')
            </if>
            <if test="email!=null and email!=''">
                and email=#{email}
            </if>
        </trim>
    </select>

//where set 替换 trim

7.2.7联表条件分页查询

//接口处
public List<Emp> selectByNameAndSal(EmpMessage empMessage);

// 可以把条件封装到实体类中vo [view object] 视图对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmpMessage {
    private String name;
    private Integer maxMoney;
    private Integer minMoney;
}


//sql查询,映射文件
<resultMap id="myMap" type="com.wjy.entity.Emp">
        <id property="id" column="empno"/>
        <result property="name" column="e_name"/>
        <result property="job" column="job"/>
        <result property="money" column="sal"/>
        <result property="deptNo" column="deptno"/>
        <association property="dept" javaType="com.wjy.entity.Dept">
            <id property="id" column="deptno"/>
            <result property="name" column="dname"/>
            <result property="loc" column="loc"/>
        </association>
    </resultMap>
<select id="selectByNameAndSal" resultMap="myMap">
        select * from emp e join dept d on d.deptno = e.DEPTNO
        <trim prefix="where" prefixOverrides="and">
            <if test="name!=null and name!=''">
                and E_NAME like concat('%',#{name},'%')
            </if>
            <if test="minMoney!=null">
                and SAL>=#{minMoney}
            </if>
            <if test="maxMoney!=null">
                and SAL&lt;=#{maxMoney}
            </if>
        </trim>
    </select>


//测试--分页查找,根据名字模糊查找,新资在某个范围段的
    @Test
    public void selByNamAndSal(){
        //打开分页
        PageHelper.startPage(1,1);
        //调用方法查找
        EmpMessage empMessage = new EmpMessage();
        empMessage.setName("佳");
        empMessage.setMinMoney(8000);
        empMessage.setMaxMoney(10000);
        List<Emp> emps = empDao.selectByNameAndSal(empMessage);
        PageInfo<Emp> pageInfo = new PageInfo<Emp>(emps);
        System.out.println("总条数:"+pageInfo.getTotal());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("当前页的信息:");
        List<Emp> list = pageInfo.getList();
        for (Emp e :
                list) {
            System.out.println(e);
        }
    }

8. mybatis代码生成器--适用于简单的crud操作

实体类,dao接口,mapper映射文件无需自己写了。

先连接数据库

可以选择需要的数据库表

老的版本需要加上时区:

选择构建的表

设置生成的位置、包名(基础包名、实体类名包名)、忽略的前后缀、父类等

根据需要

选中default-all生成的资源

9.缓存--查询才有

缓存:把磁盘中的数据放入到内存中,减少数据库的压力

数据库存储:存放到磁盘

缓存的数据:存放在内存

对比:内存的速度要比磁盘速度快,电脑重启后内存的数据会丢失。

原理:

什么样的数据适合放入缓存:

1.查询频率高的数据且修改频率低的

2.安全系数低

mybatis默认支持缓存操作

提供了两个缓存模式:

1.一级缓存(默认开启的)基于sqlSession完成

2.二级缓存(默认不开启)基于Mapper(namespace)

9.1mybatis一级缓存

根据运行结果发现查询三次,但是只执行了一次sql语句:说明其他两次都是从缓存中读取的。

@Test
    public void test01()throws Exception{
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sessionFactory.openSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Emp emp = empMapper.selectByPrimaryKey(11L);
        System.out.println("第一次查询:"+emp);
        Emp emp1 = empMapper.selectByPrimaryKey(11L);
        System.out.println("第二次查询:"+emp1);
        Emp emp2 = empMapper.selectByPrimaryKey(11L);
        System.out.println("第三次查询:"+emp2);
    }

根据运行结果得出,使用不同的sqlSession对象,发送了两次sql语句:说明一级缓存是基于sqlSession存放的

@Test
    public void test02()throws Exception{
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession1 = sessionFactory.openSession();
        EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
        Emp emp1 = empMapper1.selectByPrimaryKey(11L);
        System.out.println("第一次查询:"+emp1);

        SqlSession sqlSession2 = sessionFactory.openSession();
        EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);

        Emp emp2 = empMapper2.selectByPrimaryKey(11L);
        System.out.println("第二次查询:"+emp2);
    }

9.2mybatis二级缓存

基于mapper实现的,默认情况不开启,多个sqlSession可以共享二级缓存中的数据

1.第一次执行sql并写入到二级缓存中

2.第二次直接从缓存去读取

3.当执行插入、更新和删除操作时清空缓存区域

1.开启二级缓存--mybatis.xml文件中

<!--开启二级缓存-->

<settings>

<setting name="cacheEnabled" value="true"/>

</settings>

2.使用二级缓存--在映射文件中使用

<!--使用二级缓存 表示映射文件中所有的查询都使用二级缓存-->

<cache/>

<cache

eviction="FIFO" //回收策略为先进先出

flushInterval="60000" //自动刷新时间

60ssize="1M" //最多缓存 512 个引用对象

readOnly="true"/> //只读

<!--在标签中单独设置二级缓存-->

useCache="true/false"

第一次sqlSession1关闭之前会先提交到缓存区域,然后第二吃sqlSession2执行时会直接从缓存区读取

使用不同的sqlSession对象只发生一条sql语句

 @Test
    public void test02()throws Exception{
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession1 = sessionFactory.openSession();
        EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
        Emp emp1 = empMapper1.selectByPrimaryKey(11L);
        System.out.println("第一次查询:"+emp1);
        sqlSession1.close();//关闭sqlSession1--会先执行commit()提交,再关闭资源
        sqlSession1.commit();

        SqlSession sqlSession2 = sessionFactory.openSession();
        EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);

        Emp emp2 = empMapper2.selectByPrimaryKey(11L);
        System.out.println("第二次查询:"+emp2);
    }

如果中间执行了增删改操作,会清空缓存中的数据(一级二级都是)

@Test
    public void test02()throws Exception{
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession1 = sessionFactory.openSession();
        EmpMapper empMapper1 = sqlSession1.getMapper(EmpMapper.class);
        Emp emp1 = empMapper1.selectByPrimaryKey(11L);
        System.out.println("第一次查询:"+emp1);
        //sqlSession1.close();//关闭sqlSession1--会先执行commit()提交,再关闭资源
        sqlSession1.commit();
        SqlSession sqlSession2 = sessionFactory.openSession();
        EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
//修改
        SqlSession sqlSession3 = sessionFactory.openSession();
        EmpMapper empMapper3 = sqlSession3.getMapper(EmpMapper.class);
        Emp emp3 = new Emp(10,"s","boss",6000.0,20);
        empMapper3.updateByPrimaryKey(emp3);
        sqlSession3.commit();

        Emp emp2 = empMapper2.selectByPrimaryKey(11L);
        System.out.println("第二次查询:"+emp2);
    }

;