讨论Spring整合Mybatis时一级缓存失效得问题
问题
1、学习测试时发现了一级缓存并没有生效,先看案例:
setting配置:
<settings>
<!-- (1) 提供可控制Mybatis框架运行行为的属性信息 -->
<setting name="lazyLoadingEnabled" value="false" />
<setting name="logImpl" value="STDOUT_LOGGING" />
<setting name="localCacheScope" value="SESSION"/>
</settings>
测试代码:
@Test
public void test1(){
try(SqlSession sqlSession = sessionFactory.openSession();){
GoodsMapper goodsMapper = sqlSession.getMapper(GoodsMapper.class);
Goods goods = goodsMapper.getGoodsById(1,"电脑2");
Goods goods2 = goodsMapper.getGoodsById(1,"电脑2");
}
}
@Autowired
private GoodsMapper goodsMapper;
@Test
public void test2(){
Goods goods = goodsMapper.getGoodsById(1,"电脑2");
Goods goods2 = goodsMapper.getGoodsById(1,"电脑2");
}
问题分析
首先我们都知道一级缓存的作用范围有两种,一种是sqlSession,一种是STATEMENT。我们看test2方法,用的都是同一个mapper,按理说是应该只查询一次的啊,难道同一个mapper的sqlSession不一样。紧接着我试了test1方法,用的也都是同一个mapper,发现只查询了一次数据库。难道这两种方法有不一样的地方吗?
答案就在MapperProxy类当中,我们打断点执行test1方法,我们发现他的sqlSession类型是DefaultSqlSession

然后再执行test2方法,我们发现他的sqlSession类型是SqlSessionTemplate

他们的差别找到了,失效的原因多半就是SqlSessionTemplate造成的,SqlSessionTemplate类里有一个SqlSessionInterceptor,我们看他的invoke方法,代码如下:
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
此时我们发现sqlSession是通过invoke方法里的getSqlSession方法重新赋值了,而我打断点发现,同一个mapper调同样的方法获得的sqlSession是不一样的,既然不一样,那当然读不到缓存了。
而DefaultSqlSession则是直接执行查询方法,是同一个sqlSession。所以读到了缓存。
讨论Spring整合Mybatis时一级缓存失效得问题的更多相关文章
- spring管理hibernate,mybatis,一级缓存失效原因
mybatis缓存:一级缓存和二级缓存 hibernate缓存:一级缓存和二级缓存 关于缓存: 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器, 其作用是为了减少应 ...
- 简单探讨spring整合mybatis时sqlSession不需要释放关闭的问题
https://blog.csdn.net/RicardoDing/article/details/79899686 近期,在使用spring和mybatis框架编写代码时,sqlSession不需要 ...
- spring整合mybatis后,mybatis一级缓存失效的原因
一般来说,可以在5个方面进行缓存的设计: 最底层可以配置的是数据库自带的query cache, mybatis的一级缓存,默认情况下都处于开启状态,只能使用自带的PerpetualCache,无法配 ...
- 分析下为什么spring 整合mybatis后为啥用不上session缓存
因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...
- 2017年2月16日 分析下为什么spring 整合mybatis后为啥用不上session缓存
因为一直用spring整合了mybatis,所以很少用到mybatis的session缓存. 习惯是本地缓存自己用map写或者引入第三方的本地缓存框架ehcache,Guava 所以提出来纠结下 实验 ...
- Spring Boot 整合mybatis时遇到的mapper接口不能注入的问题
现实情况是这样的,因为在练习spring boot整合mybatis,所以自己新建了个项目做测试,可是在idea里面mapper接口注入报错,后来百度查询了下,把idea的注入等级设置为了warnin ...
- MyBatis之一级缓存及其一级缓存失效
定义: 一级缓存:本地缓存:与数据库同一次会话(sqlSession)期间查询到的数据会放在本地缓存中,如果以后要获取相同的数据直接从缓存中获取,不会再次向数据库查询数据一个SqlSession拥有一 ...
- Mybatis之一级缓存(七)
1. 介绍 Mybatis缓存分为一级缓存和二级缓存,在本节中我们介绍下一级缓存的使用及其特性 MyBatis的一级缓存是在一个Session域内有效的,当Session关闭后,缓存内容也随之销毁.缓 ...
- 深入源码理解Spring整合MyBatis原理
写在前面 聊一聊MyBatis的核心概念.Spring相关的核心内容,主要结合源码理解Spring是如何整合MyBatis的.(结合右侧目录了解吧) MyBatis相关核心概念粗略回顾 SqlSess ...
随机推荐
- ECMAScript 2015 迭代器协议:实现自定义迭代器
迭代器协议定义了一种标准的方式来产生一个有限或无限序列的值,并且当所有的值都已经被迭代后,就会有一个默认的返回值. 当一个对象只有满足下述条件才会被认为是一个迭代器:它实现了一个 next() 的方法 ...
- jQuery遍历集合
jQuery 遍历List集合 $(function(){ var tbody = ""; var obj =[{"name ":"xxxx&quo ...
- activity知识点
一:activity的理解 1.活动:四大应用组件之一 2.作用:提供能让用户操作并与之交互的界面 3.组件的特点: 它的类必须实现特定接口或继承特定类 需要在配置文件中配置全类名 它的对象不是通过n ...
- 实现自己的DiscoveryClient
需要做的: DiscoveryClient能提供那些服务的服务名列表 返回指定服务对于的ServiceInstance列表 返回DiscoveryClient的顺序 返回HealthIndicator ...
- c# 获取 Apk ,Aar 文件包名
最近项目有个需求,需要拿到前端上传的Apk或者Aar文件里面的包名. 在这里贡献出来,方便有需求的小伙伴. 项目是 asp.net core 2.2 需要安装 nuget : AndroidXml S ...
- App.Config操作
public class ConfigUtils { public static string filename = System.Windows.Forms.Application.StartupP ...
- ob_start()、ob_get_contents() 等使用方法
ob_start()ob_get_contents(); 获取缓冲区内容ob_end_clean():删除内部缓冲区的内容,并且关闭内部缓冲区 ob_end_flush() 发送内部缓冲区的内容到浏览 ...
- jieba库的使用
jieba库的使用 jeiba库是一款很优秀的用于中文分词的第三方库,它通过一个汉词词典来确定汉字之间的关联概率,将概率较大的组成分词. 精准模式 把文本精准的分割开来,不存在冗余单词. jieba. ...
- BZOJ-3143/洛谷3232 游走(HNOI2013)概率DP
题意:给定n个点m条边.每条边的权值还没决定,权值大小为从1到m.从1出发每次等概率选一条出边向下走,直到走到n点停止,路径代价就是边权总和.由你来决定边权来使得上诉路径代价期望值最小. 解法:点这么 ...
- 如何触发react input change事件
页面用react来进行开发的,想触发react组件里面input的change事件,用Jquery的trigger来触发没有效果,必须使用原生的事件来进行触发. var event = new Eve ...