SSM系列4 Mybatis缓存策略与分页组件PageHelper

继上一篇笔记 SSM系列3 Mybatis快速上手,今天学习了一下Mybatis的分页组件与缓存策略,直接上干货

Mybatis的缓存策略

Mybatis缓存策略有两级缓存:
一级缓存:默认开启,缓存范围为一次SqlSession会话,session关闭,该缓存即清空
二级缓存:手动开启,缓存范围为mapper的namespace中,比一级缓存范围大,生存时间长
一级缓存无论何种操作,进行了commit之后都会被清空
二级缓存的commit的操作,只有在写操作commit之后才会被清空,查询后的commit操作不会清空缓存

一级缓存

代码演示:

/*缓存测试*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-对象1:"+goods);
        Goods goods2 = session.selectOne("goods.findById",739);
        System.out.println("session1-对象2:"+goods2);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-对象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

我们看如下结果,在同一个session中,进行两次查询,但是只去数据库查询了一次,并且两次接收到的对象是同一个对象,在第二个session中查询同一条数据,又去数据库查询了一次,这说明一级缓存的作用域是一个session会话周期
在这里插入图片描述

commit 清空缓存测试

/*缓存测试*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-对象1:"+goods);
        session.commit();//清空缓存
        Goods goods2 = session.selectOne("goods.findById",739);
        System.out.println("session1-对象2:"+goods2);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

看下图结果,去数据库进行了两次查询,并且对象也不一样,所以commit清空缓存的成立的
在这里插入图片描述

禁用缓存

一级缓存可以使用flushCache禁用,用法是在相关的mapper.xml的Sql标签后面加上flushCache=“true”
flushCache:强制清空缓存,并且该Sql执行后无论得到什么结果都不会对其进行缓存

<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" flushCache="true">
   select * from t_goods where goods_id = #{value }
</select>

继续用刚才的测试代码测试,结果如下,下面我也不说太多了,自己看代码,看结果
在这里插入图片描述

二级缓存

二级缓存开启就需要一些配置了
mybatis-config.xml里settings里增加setting项,开启二级缓存

<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>

相应的mapper.xml我这里是goods.xml里增加cache标签

<!--
    cache:标签用于配置二级缓存策略
    eviction:是缓存的清除策略,当缓存对象数量达到上限后,自动触发对应策略对缓存对象进行清除
        1.LRU:最近最少使用的,移除最长时间没有被使用的对象
        2.FIFO:先进先出,按对象进入缓存的顺序进行移除
        3.SOFT:软引用:移除基于JVM垃圾收集器状态和软引用规则来移除对象
        4.WEAK:弱引用:更积极的移除基于JVM垃圾收集器状态和弱引用的对象
    flushInterval:间隔多长时间自动清空缓存,单位毫秒,600000毫秒=10分钟
    size:缓存存储上限,用于保存对象或集合(一个集合=一个对象)的数量上限
    readOnly:
        true:返回只读缓存,每次从缓存取出的是缓存对象本身,执行效率高
        false:每次取出的是缓存对象的副本,每一次取出的对象都是不同的,安全性高
    -->
<cache eviction="LRU" flushInterval="6000000" size="512" readOnly="true"/>

测试

记得把flushCache选项去掉,这个在二级缓存里也是起作用的

/*缓存测试*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-对象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-对象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

结果:第二次也没有去数据库进行查询,直接将第一次查询的缓存对象取出来了
在这里插入图片描述

缓存清空策略

一级缓存清空策略上面已经说过了,利用commit,与flushCache可以清空缓存
二级缓存不一样喽,可以利用flushCache="true"清空缓存,useCache="false"禁用缓存
flushCache刚才已经说过了,这里不再说了,大家可以自己测试,这里说一下useCache="false"禁用缓存,跟flushCache一样,在Sql相关标签上加上即可

<select id="findById" parameterType="Integer" resultType="com.zhangyx.mybatis.entity.Goods" useCache="false">
        select * from t_goods where goods_id = #{value }
</select>

由于一级缓存的存在,这里测试需要放在两个session会话里

/*缓存测试*/
@Test
public void testFindById(){
    SqlSession session = null;
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session1-对象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",739);
        System.out.println("session2-对象1:"+goods);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

两次查询,两个对象
在这里插入图片描述

写操作缓存策略

写操作都没有缓存,因为写操作上面的flushCache默认是开启的,就以更新为例看一下

@Test
public void testUpdate(){
    SqlSession session = null;
    //openSession创建一个新的Sqlsession对象,Sqlsession提供了增删改查的方法调用
    try {
        session = sessionFactory.openSession();
        Goods goods = session.selectOne("goods.findById",2675);
        System.out.println(goods);
        goods.setTitle("数据更新测试");
        goods.setSubTitle("数据更新测试第二标题");
        goods.setCategoryId(1);
        goods.setCurrentPrice(1000f);
        goods.setDiscount(2f);
        goods.setIsFreeDelivery(1);
        goods.setOriginalCost(20f);
        session.update("goods.update", goods);
//            session.commit();//清队缓存干扰去掉
    }catch (Exception e){
        e.printStackTrace();
        session.rollback();
    }finally {
        if(session != null){
            //将Connection归还到连接池供其他Session重用
            session.close();
        }
    }
    try {
        session = sessionFactory.openSession();
        Goods goods1 = session.selectOne("goods.findById",2675);
        System.out.println(goods1);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            session.close();
        }
    }
}

在这里插入图片描述

使用分页插件粗略步骤

其实官网有详细教程:https://pagehelper.github.io/docs/howtouse/
1.引入PageHelper与jsqlparser核心jar包
2.mybatis-config.xml增加有关PageHelper的Plugin配置
3.代码中查询数据库代码的上方直接使用PageHelper.startPage()自动分页

pom.xml引入Mybatis分页组件PageHelper

<!--Mybatis自动分页 https://pagehelper.github.io/docs/howtouse/ -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.4</version>
</dependency>
<!--Mybatis自动分页所需的sql解析器-->
<dependency>
	<groupId>com.github.jsqlparser</groupId>
	<artifactId>jsqlparser</artifactId>
	<version>0.9.5</version>
</dependency>

mybatis-config.xml增加plugin配置

<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
    	<!--使用的是哪个数据库,不写也没有关系,会根据jdbc驱动自动判断-->
    	<property name="helperDialect" value="mysql"/>
	    <!--分页合理化,开启后,如果查的是第0页则会自动查第一页,
    	如果查的页面数超过总页数,则会去查最后一页-->
    	<property name="reasonable" value="true"/>
    </plugin>
</plugins>

测试

@Test
public void testFindAll(){
    SqlSession session = null;
    //openSession创建一个新的Sqlsession对象,Sqlsession提供了增删改查的方法调用
    try {
        session = sessionFactory.openSession();
        //selectList用于查询多条数据
        //表.xml里对应的namespace.sqlId
        //分页组件,直接在查询代码上方加入PageHelper.startPage()即可
        PageHelper.startPage(0,10);
        List<Goods> list = session.selectList("goods.findAll");
        for (Goods goods : list){
            System.out.println(goods.getTitle());
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        if(session != null){
            //将Connection归还到连接池供其他Session重用
            session.close();
        }
    }
}

运行结果
在这里插入图片描述

如果分页插件里指定的跟自己使用的数据库不一样,比如说指定了oracle,但是我们使用的是mysql会发生什么情况呢
我们看到,虽然指定的数据库错了,但是分页组件还是按照oracle的形式把要其所用的sql语句组装了起来,只不过组装的是oracle可以用的分页语句

在这里插入图片描述
Mybatis告一段落,但是在实际项目开发中,sqlSessionFactory不是这样使用的,需要配置到xml文件里的,会在我后面的笔记:Spring SpringMVC Mybatis FreeMarker 整合里作记录

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章