java-mybaits-014-数据库缓存设计【querycache、mybatis一级缓存、二级缓存】
一、概述
一般来说,可以在5个方面进行缓存的设计:
1、最底层可以配置的是数据库自带的query cache,
2、mybatis的一级缓存,默认情况下都处于开启状态,只能使用自带的PerpetualCache,无法配置第三方缓存
3、mybatis的二级缓存,可以配置开关状态,默认使用自带的PerpetualCache,但功能比较弱,能够配置第三方缓存,
4、service层的缓存配置,结合spring,可以灵活进行选择
5、针对实际业务情况,直接缓存部分html页面,直接返回给客户端。
1.1、一级缓存失效【结合spring后失效,service加上@Transactional后可以使用】
在测试过程中,发现mybatis的一级缓存没有起作用,失效了。经过调研,发现是由于以下原因引起的:
1.mybatis的一级缓存生效的范围是sqlsession,是为了在sqlsession没有关闭时,业务需要重复查询相同数据使用的。一旦sqlsession关闭,则由这个sqlsession缓存的数据将会被清空。
2.spring对mybatis的sqlsession的使用是由template控制的,sqlSessionTemplate又被spring当作resource放在当前线程的上下文里(threadlocal),spring通过mybatis调用数据库的过程如下:
1、我们需要访问数据
2、spring检查到了这种需求,于是去申请一个mybatis的sqlsession(资源池),并将申请到的sqlsession与当前线程绑定,放入threadlocal里面
3、sqlSessionTemplate从threadlocal获取到sqlsession,去执行查询
4、查询结束,清空threadlocal中与当前线程绑定的sqlsession,释放资源
5、我们又需要访问数据
6、返回到步骤2
通过以上步骤后发现,同一线程里面两次查询同一数据所使用的sqlsession是不相同的,所以,给人的印象就是结合spring后,mybatis的一级缓存失效了。
而在spring中一般都是用sqlSessionTemplate,如下
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:configuration.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:com/hejb/sqlmap/*.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
在SqlSessionTemplate中执行SQL的session都是通过sqlSessionProxy来,sqlSessionProxy的生成在构造函数中赋值,如下:
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
sqlSessionProxy通过JDK的动态代理方法生成的一个代理类,主要逻辑在InvocationHandler对执行的方法进行了前后拦截,主要逻辑在invoke中,包好了每次执行对sqlsesstion的创建,commit,关闭
代码如下:
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 每次执行前都创建一个新的sqlSession
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的缓存了.
对于开启了事务为什么可以用上呢, 跟入getSqlSession方法
如下:
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
// 首先从SqlSessionHolder里取出session
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Creating a new SqlSession");
}
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
在里面维护了个SqlSessionHolder,关联了事务与session,如果存在则直接取出,否则则新建个session,所以在有事务的里,每个session都是同一个,故能用上缓存了
发的
java-mybaits-014-数据库缓存设计【querycache、mybatis一级缓存、二级缓存】的更多相关文章
- Mybatis一级、二级缓存
Mybatis一级.二级缓存 一级缓存 首先做一个测试,创建一个mapper配置文件和mapper接口,我这里用了最简单的查询来演示. <mapper namespace="c ...
- 170214、mybatis一级和二级缓存
mybatis一级缓存是指在内存中开辟一块区域,用来保存用户对数据库的操作信息(sql)和数据库返回的数据,如果下一次用户再执行相同的请求, 那么直接从内存中读数数据而不是从数据库读取. 其中数据的生 ...
- MyBatis 一级、二级缓存
一级 默认session就有一级缓存,session有C/U/D操作或者session.clearCache();session.commit();都会清空缓存: 二级在mapper.xml中添加&l ...
- Mybatis使用Redis二级缓存
在Mybatis中允许开发者自定义自己的缓存,本文将使用Redis作为Mybatis的二级缓存.在Mybatis中定义二级缓存,需要如下配置: 1. MyBatis支持二级缓存的总开关:全局配置变量参 ...
- Spring + MySQL + Mybatis + Redis【二级缓存】执行流程分析
一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就 ...
- Mybatis自定义分布式二级缓存实现与遇到的一些问题解决方案!
先说两句: 我们都知道Mybatis缓存分两类: 一级缓存(同一个Session会话内) & 二级缓存(基于HashMap实现的以 namespace为范围的缓存) 今天呢, 我们不谈一级缓存 ...
- 【mybatis源码学习】mybtias一级,二级缓存
转载:https://www.cnblogs.com/ysocean/p/7342498.html mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解: ①.一级缓存是SqlSessi ...
- Spring + MySQL + Mybatis + Redis【二级缓存】
一.Redis环境 Redis 官网 :http://redis.io/ windows下载:https://github.com/dmajkic/redis/downloads 1.文件解压缩 2. ...
- 【MyBatis学习13】MyBatis中的二级缓存
1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加 ...
- mybatis整合redis二级缓存
mybatis默认开启了二级缓存功能,在mybatis主配置文件中,将cacheEnabled设置成false,则会关闭二级缓存功能 <settings> <!--二级缓存默认开启, ...
随机推荐
- js中string常用方法
charAt(index) 用于返回指定位置的字符,index从0开始计算 concat(string1,string2..),用于字符串拼接: indexOf():用于返回指定字符在字符串中第一次出 ...
- java常用日期类型转换
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import j ...
- service worker(二)之主页面与service worker通信
实现一个主页面发送消息,worker搜到信息向所有的页面派发消息(当前页面除外) msg.html <!DOCTYPE html> <html lang="en" ...
- Xshell5 安装JDK
.执行命令yum -y list java*查看可安装java版本.执行成功后可以看见如下的结果 安装java-1.8全部相关 yum install -y java-1.8.0-openjdk* 使 ...
- AJAX备忘
基础 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法. AJAX ...
- 洛谷P1162(自我感觉思路还算巧妙的一道题)
P1162 填涂颜色 题目描述 由数字0 组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向.现要求把闭合圈内的所有空间都填写成2.例如:6X6的方阵(n=6),涂色前和 ...
- Safe Path(bfs+一维数组存图)
题目链接:http://codeforces.com/gym/101755/problem/H 题目分析:先bfs一遍怪兽可以到达的点,再bfs人可以走的地方看可不可以到达终点: 很显然读到 2&l ...
- Large-Scale Oil Palm Tree Detection from High-Resolution Satellite Images Using Two-Stage Convolutional Neural Networks(worldview油棕树检测)
不是目标检测也不是语义分割,两步CNN指的是,采集的数据是一堆点,以点为中心的65*65和17*17图像范围大小来判断这个点是否是油棕树.第一步就是判断65*65的范围是否为(油棕树植被群,其他植被/ ...
- Redis企业实战的几个坑
一.前言 小伙伴们对Redis应该不陌生,Redis是系统必备的分布式缓存中间件,主要用来解决高并发下分担DB资源的负载,从而提升系统吞吐量. Redis支持多种数据类型,String(字符串).li ...
- PIT 编辑器编辑及协同架构说明
pit 项目使用 quill-delta 作为数据层存储文档内容数据,quill-delta 是一个基于 OT 算法的库,用 quill-delta 作为数据层,不仅能很好的保存文档数据,还可以方便的 ...