MyBatis二级缓存带来的问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis二级缓存带来的问题相关的知识,希望对你有一定的参考价值。
参考技术A MyBatis二级缓存使用的在某些场景下会出问题,来看一下为什么这么说。假设我有一条select语句(开启了二级缓存):
selecta.col1, a.col2, a.col3, b.col1, b.col2, b.col3fromtableA a, tableB bwherea.id= b.id;
对于tableA与tableB的操作定义在两个Mapper中,分别叫做MapperA与MapperB,即它们属于两个命名空间,如果此时启用缓存:
MapperA中执行上述sql语句查询这6个字段
tableB更新了col1与col2两个字段
MapperA再次执行上述sql语句查询这6个字段(前提是没有执行过任何insert、delete、update操作)
此时问题就来了,即使第(2)步tableB更新了col1与col2两个字段,第(3)步MapperA走二级缓存查询到的这6个字段依然是原来的这6个字段的值,因为我们从CacheKey的3组条件来看:
<select>标签所在的Mapper的Namespace+<select>标签的id属性
RowBounds的offset和limit属性,RowBounds是MyBatis用于处理分页的一个类,offset默认为0,limit默认为Integer.MAX_VALUE
<select>标签中定义的sql语句
对于MapperA来说,其中的任何一个条件都没有变化,自然会将原结果返回。
这个问题对于MyBatis的二级缓存来说是一个无解的问题,因此使用MyBatis二级缓存有一个前提: 必须保证所有的增删改查都在同一个命名空间下才行 。
MyBatis的二级缓存
文章目录
MyBatis的二级缓存
MyBatis默认是开启一级缓存的
MyBatis默认开启了一级缓存,但是它的一级缓存的作用域是同一个SqlSession对象,就是说只有当两个sql语句完全一样,并且都是通过同一个SqlSession对象操作数据库的时候,MyBatis的一级缓存才会生效,当执行一个和前面完全一样的sql语句的时候,这样就不会重新连接数据库从磁盘中取数据了,而是从一级缓存中(内存中)直接取数据。
但是一级缓存不实用,因为我们调用同一个动态代理接口的方法的时候,每次调用一个方法无论相同不相同都会重新创建一个SqlSession对象。因此我们在实际项目中基本上用不到一级缓存,如果想要提高数据库的查询性能,需要用二级缓存。
开启MyBatis的二级缓存
为什么要开启二级缓存
为什么要开启MyBatis的二级缓存呢?看下面的这个图:
就是当调用同一个动态代理接口的同一个方法两次的时候,其实是会创建两个SqlSession对象操作数据库,所以一级缓存是不起作用的,这个时候我们就需要开启二级缓存了。
在mybatis的配置文件中进行配置
在对应的mapper映射文件中声明
想要给哪个动态代理接口开启二级缓存,就在哪个对应的mapper映射文件中声明一下,如下图:
相关的DO对象需要实现序列化
测试
首先启动项目,然后连续访问这个项目中的/query接口两次,如下图:
动态代理接口执行更新方法后会清空对应的二级缓存
比如:
goodsMapper动态代理接口相关的二级缓存中有条数据[Student:(id:1,name:“zs”)],现在我们更新了数据库中的相关数据为[Student:(id:1,name:“ls”)],那么我们假如没有清空二级缓存,下次再查询id为1的学生的时候,因为sql语句和之前的一样,那么就会去二级缓存中查找,这时候查找到的就是[Student:(id:1,name:“zs”)],但是此时这个数据是错误的,因为我们数据库中已经更新了这条数据为[Student:(id:1,name:“ls”)]。因此动态代理接口每次进行完更新操作之后都刷新二级缓存清空里面的数据,这是非常合理的。
使用二级缓存的好处
可以提高数据库的查询性能,优化数据库的查询操作,提高性能。就是,使用缓存可以把数据库的查询结果存储在内存中,这样如果下次我们进行相同的查询的时候,就不用连接数据库读取电脑磁盘中的数据了,而可以直接通过内存读取数据。
以上是关于MyBatis二级缓存带来的问题的主要内容,如果未能解决你的问题,请参考以下文章