Mybatis缓存

本文详细介绍了MyBatis的一级和二级缓存机制,包括一级缓存的工作流程、失效情况,以及二级缓存的开启步骤和相关属性。通过代码示例展示了如何在实际操作中应用缓存,解释了不同参数调用如何影响缓存效果,并分析了缓存命中率。同时,讨论了二级缓存的配置选项,如回收策略、刷新间隔等,以及如何实现序列化来配合二级缓存。
摘要由CSDN通过智能技术生成

缓存简介

mybatis缓存有两级,一级缓存和二级缓存。缓存中存放的是查询语句查询到的结果。作用是减轻数据库的访问压力,当同一个查询要访问第二次时,就不用再从数据库中取数据,直接从缓存中取数据。

缓存示例图

工作机制:
	一级缓存,默认开启,是sqlsession级别的,也就是一次会话。
	二级缓存,需要手动开启,是namespace级别的,也就是一个映射文件就是一个缓存。
	流程描述:当一个数据查询语句开始时,第一次访问内存,内存中是没有数据的,就方法数据库,将查询出来的数据放在一级缓存中。当sqlsession关闭或者提交后,一级缓存中的数据就会交给对应的二级缓存,此时二级缓存才有数据。
	访问流程是:先二级缓存,再一级缓存,再数据库
	缓存的存储方式是key-value形式,一级缓存的key是sqlsession标识+方法名+参数名。二级缓存的key是namespace标识+方法名+参数。

代码操作

1、一级缓存

(1)同sqlSession同方法同参数

    public static void main(String[] args) throws Exception {
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
        SqlSession sqlSession = build.openSession();
        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
        Account account = mapper.selectByPrimaryKey(1);
        System.out.println(account);
        Account account1 = mapper.selectByPrimaryKey(1);
        System.out.println(account1);
    }
如上示例:我们使用的同一个sqlSession访问数据库,方法相同,参数相同,我们看结果。
2021-03-24 20:59:00,077 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==>  Preparing: select id, name, money, isdeleted, created, updated from account where id = ? 
2021-03-24 20:59:00,105 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==> Parameters: 1(Integer)
2021-03-24 20:59:00,291 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - <==      Total: 1
Account{id=1, name='小明', money=3000.0, isdeleted=0, created=Tue Mar 02 14:45:26 CST 2021, updated=Fri Mar 12 14:45:32 CST 2021}
Account{id=1, name='小明', money=3000.0, isdeleted=0, created=Tue Mar 02 14:45:26 CST 2021, updated=Fri Mar 12 14:45:32 CST 2021}
结果显示:只有第一次访问发送了sql语句,第二次直接打印出了结果。

(2)同sqlSession同方法不同参数

public static void main(String[] args) throws Exception {
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
        SqlSession sqlSession = build.openSession();
        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
        Account account = mapper.selectByPrimaryKey(1);
        System.out.println(account);
        Account account1 = mapper.selectByPrimaryKey(2);
        System.out.println(account1);
    }
如上示例:我们使用的同一个sqlSession访问数据库,方法相同,参数不同,我们看结果。
2021-03-24 21:10:27,329 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==>  Preparing: select id, name, money, isdeleted, created, updated from account where id = ? 
2021-03-24 21:10:27,370 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==> Parameters: 1(Integer)
2021-03-24 21:10:27,396 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - <==      Total: 1
Account{id=1, name='小明', money=3000.0, isdeleted=0, created=Tue Mar 02 14:45:26 CST 2021, updated=Fri Mar 12 14:45:32 CST 2021}
2021-03-24 21:10:27,397 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==>  Preparing: select id, name, money, isdeleted, created, updated from account where id = ? 
2021-03-24 21:10:27,397 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==> Parameters: 2(Integer)
2021-03-24 21:10:27,408 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - <==      Total: 1
Account{id=2, name='小乐', money=1500.0, isdeleted=2, created=Tue Mar 09 14:46:43 CST 2021, updated=Mon Mar 22 14:46:48 CST 2021}
结果显示:发送了两次sql,这是因为虽然两次的sqlsession和方法名相同,但是参数不同,第一次的结果存储到了一级缓存,但是第二个请求的参数和第一个不同,再一级缓存中找不到,就到数据库查询。

(3)一级缓存失效的情况

①同sqlsession同方法不同参数
②不同sqlsession
③同一个sqlsession两次查询中进行了增删改,增删改操作会清空缓存
④手动清空缓存

2、二级缓存

二级缓存需要手动开启,二级缓存的作用域是按namespece划分。当一级缓存被关闭或者提交,一级缓存中的内容就会存到二级缓存中。

第一步: 先在mybatis的配置文件中开启缓存

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

第二步: 在映射文件中开启缓存,因为二级缓存是按namespace划分的

<cache/>
可以只写一个cache标签,也可以手动设置一些属性:
eviction:缓存的回收策略
	LRU:最近最少使用的        默认
	FIFO:先进先出
	SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
	WEAK:弱引用,更积极的移除基于垃圾回收器状态和软引用规则的对象
flushInterval:缓存刷新间隔
	缓存多久清空一次,默认不清空,设置毫秒值
readonly:是否只读
	true:只读:mybatis默认所有从缓存中获取数据的操作都是只读操作,不会更改数据。mybatis为了提高速度,直接将缓存中数据的引用地址交给用户,不安全,速度快
	false:非只读:mybatis默认所有的操作数据不是只读操作,所以mybatis会将用户要读取的数据复制一份交给用户,安全,速度慢
size:缓存空间的大小
type:自定义缓存的全类名

第三步: 我们的POJO类都要实现序列化接口

第四步:代码测试

public static void main(String[] args) throws Exception {
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
       
//        第一个会话
        SqlSession sqlSession = build.openSession();
        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
        Account account = mapper.selectByPrimaryKey(1);
        System.out.println(account);
//        会话关闭,一级缓存的内容就会存储到二级缓存中
        sqlSession.close();

//      开启第二个会话
        SqlSession sqlSession1 = build.openSession();
        AccountMapper mapper1 = sqlSession1.getMapper(AccountMapper.class);
        Account account1 = mapper1.selectByPrimaryKey(1);
        System.out.println(account1);
    }
结果如下:
2021-03-25 22:53:07,026 [main] DEBUG [com.fy.dao.AccountMapper] - Cache Hit Ratio [com.fy.dao.AccountMapper]: 0.0
2021-03-25 22:53:07,338 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==>  Preparing: select id, name, money, isdeleted, created, updated from account where id = ? 
2021-03-25 22:53:07,380 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - ==> Parameters: 1(Integer)
2021-03-25 22:53:07,405 [main] DEBUG [com.fy.dao.AccountMapper.selectByPrimaryKey] - <==      Total: 1
Account{id=1, name='2323', money=123123.0, isdeleted=1, created=Wed Mar 10 00:00:00 CST 2021, updated=Fri Mar 12 00:00:00 CST 2021}
2021-03-25 22:53:07,421 [main] DEBUG [com.fy.dao.AccountMapper] - Cache Hit Ratio [com.fy.dao.AccountMapper]: 0.5
Account{id=1, name='2323', money=123123.0, isdeleted=1, created=Wed Mar 10 00:00:00 CST 2021, updated=Fri Mar 12 00:00:00 CST 2021}
分析:当第一个会话访问数据库时,先查询二级缓存,二级缓存没有,再查询一级缓存,里边也没有数据,就发sql查询数据库。第二个会话是在第一个会话关闭后访问的,所以访问二级缓存就可以读取到数据了。

3、二级缓存相关属性

(1)、cacheEnabled:该属性默认是false,二级缓存不可用,一级缓存默认可用。开启二级缓存手动开起。
(2)、useCache:该属性存在于每一个select查询语句中,默认值为true,如果改为false,则该select语句的二级缓存就不能使用。
(3)、flushCache:该属性是每一个增删改中的,默认为true。每当执行过增删改语句后,一级二级缓存都会被清空。查询语句中也有该属性,值默认为false.
(4)、sqlsession.clearCache():清空一级缓存
(5)、localCacheScope:本地缓存作用域:session:本地会话的所有数据都会保存再本地缓存中。STATEMENT:停用一级缓存
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值