Mybatis的一级缓存和二级缓存

本文详细介绍了Mybatis的一级缓存和二级缓存的作用域及其工作原理。一级缓存作用于单个SqlSession,二级缓存则跨多个SqlSession。一级缓存默认开启,二级缓存需要全局和namespace级别的配置。在增删改操作后,一级缓存会被清空,确保数据一致性。二级缓存只有在提交事务后才会生效。通过示例代码展示了未提交事务时和提交事务后的查询行为,揭示了缓存的使用情况。
摘要由CSDN通过智能技术生成

Mybatis的一级缓存和二级缓存

作用域

一级缓存的作用域是session

二级缓存的作用域是namespace

一级缓存

一级缓存交于Executor维护的,在BaseExecutor下有一个PerpetualCache类型的属性,这个就是一级缓存。因为每一个SqlSession都有一个Executor,即代表着,每一个Session都有着独立的一级缓存PerpetualCache。

当用户发起查询请求时,是SqlSession会先去缓存中查找,如果有数据就返回数据,如果,没有就再去数据库查找。

但是,在用户在进行增删改的操作时,此时数据库的数据有改变,此时会清空一级缓存,即执行commit操作时,这是为了保证数据可见性。

 public static void main(String[] args) {
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            DormDao mapper = sqlSession.getMapper(DormDao.class);
            System.out.println(">>>>>>>>>>>>>>>>>>>>>");
            Dorm dorm1 = mapper.selectByPrimaryKey("A1-101");
            System.out.println(dorm1);
//            System.out.println(">>>>>>>>>>>>>>>>>>>>>");
//            Dorm dorm3 = new Dorm();
//            dorm3.setId("A1-101");
//            dorm3.setDormno("1");
//            dorm3.setRoomno("121");
//            dorm3.setDormname("A");
//            mapper.updateByPrimaryKey(dorm3);
//            sqlSession.commit();
            System.out.println(">>>>>>>>>>>>>>>>>>>>>");
            Dorm dorm2 = mapper.selectByPrimaryKey("A1-101");
            System.out.println(dorm2);

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

上面的代码在没有进行增删改的时候是第二次查询时使用的缓存,并没有发送sql语句到数据库。不提交时,使用的还是缓存。

二级缓存

二级缓存的配置

  • 全局总开关

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

    <cache/>
    
  • 可在具体的xml语句中禁止使用二级缓存 useCache=flase

配置好二级缓存之后,sqlsession的执行流程变为二级缓存 -> 一级缓存 或者 二级缓存-> 数据库。

二级缓存更像是所有一级缓存的统一,通过一个hashMap将所有一级缓存统一起来,当sqlsession执行是,会先去确认二级缓存中包含的一级缓存的信息,当sqlsession执行commit操作时,会调用tcm的comm犯法方法,此时对应的缓存信息才能被保存到二级缓存中去。

 public static void main(String[] args) {
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
            DormDao mapper = sqlSession.getMapper(DormDao.class);
            DormDao mapper1 = sqlSession1.getMapper(DormDao.class);
            System.out.println(">>>>>>>>>>>>>>>>>>>>>");
            Dorm dorm1 = mapper.selectByPrimaryKey("A1-102");
            System.out.println(dorm1);
//            sqlSession.commit();

            System.out.println(">>>>>>>>>>>>>>>>>>>>>");
            Dorm dorm4 = mapper1.selectByPrimaryKey("A1-102");
            System.out.println(dorm4);
            

        } catch (IOException e) {
            e.printStackTrace();
        }


    }

当没有进行sqlSession.commit()是输出结果如下

>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1436664465.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55a1c291]
DEBUG [main] - ==>  Preparing: select id, dormname, dormno, roomno from dorm where id = ? 
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <==      Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 2147046752.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7ff95560]
DEBUG [main] - ==>  Preparing: select id, dormname, dormno, roomno from dorm where id = ? 
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <==      Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)

Process finished with exit code 0

可见此时的二级缓存并没有起作用

当进行提交之后sqlSession.commit()输出结果如下

>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.0
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Created connection 1436664465.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55a1c291]
DEBUG [main] - ==>  Preparing: select id, dormname, dormno, roomno from dorm where id = ? 
DEBUG [main] - ==> Parameters: A1-102(String)
DEBUG [main] - <==      Total: 1
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)
>>>>>>>>>>>>>>>>>>>>>
DEBUG [main] - Cache Hit Ratio [com.zelin.MybatisDemo.DormDao]: 0.5
Dorm(id=A1-102, dormname=A, dormno=1, roomno=102)

总结

对网络上的大部分关于一级缓存以及二级缓存的执行流程我提出异议

大部分讲的都是执行流程为
二级 -->一级 -->数据库
而我觉得的执行流程是
二级 -->一级
或者
二级 -->数据库
**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值