mybatis的一级缓存的生命周期是一个sqlSession
spring 结合mybatis 可以使用mybatis的一级缓存吗
spring 中执行 mybatis的sql执行上的执行对象是 SqlSessionTemplate, 下面看看它的创建策略
1 | public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, |
使用了jdk的动态代理实现了切面的效果, 在 SqlSessionInterceptor, 下面看下 SqlSessionInterceptor 做了什么
1 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
它会为每个sql创建SqlSession,销毁SqlSession,也就说通过spring 使用Mybatis, mybatis的一级缓存并不会被使用到, 因为一个sql一个session.
所以, spring 继承mybatis 可以使用mybatis的一级缓存吗. 答案是不能
spring 结合mybatis使用二级缓存
在分布式环境下, 建议使用 ehcache 和redis , memacache 做二级缓存
key 怎么生成的呢
org.apache.ibatis.executor.BaseExecutor中生成的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) throw new ExecutorException("Executor was closed.");
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
cacheKey.update(parameterObject);
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
cacheKey.update(metaObject.getValue(propertyName));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
cacheKey.update(boundSql.getAdditionalParameter(propertyName));
}
}
}
}
return cacheKey;
}
从上面看 namesapce + sql参数 + 分页参数 + sql + TypeHanlder.class 的hashCode一致, 就认为是同样的查询.
如何保证cache命中
在分布式环境中, 如果只有一个应用走cache, namesapce,TypeHanlder, parameterObject,必定是一致的, 其他的参数自然地传入即可。 这样是可以自然命中的。
如果是多个应用, 需要保证namesapce, TypeHanlder, parameterObject的hashCode一致, 需要在代码规范上下工夫, 团队内强制保证一致, 不然很容易保证不一致的情况. 比较理想的办法, 统一多个项目的数据库访问层, 对外提供service输出, 应用不直接访问数据库。 这种情况属于垂直拆分。 一般只有在业务中后期才这样做。
cache策略怎么设置
同时, 在使用时, 同样的sql针对不同的服务, 时效性是不一样的. 所以建议cache 默认不生效, 在单个sql上去开启cache. 同样的数据sql如果有cache场景不应可以定义两个id, 对应不同的cache策略
全局开启, 在指定namesapce开启. 这样就可以开启对应namesapce的缓存了. 但是这样会默认所有的sql都走cache, 所以可以在具体的需要强一致性的sql关闭缓存
todo
spring的缓存接口, 和mybatis的缓存区别, 如何使用
jpa的二级缓存
正确的web应用打开方式. entityService + cache. 禁止使用关联查询
关联查询和entityService哪个对数据库的压力大, 各自有什么好处和坏处(好处是entityService可以更准确地cache)
jpa的会话与事务
jpa的缓存原理与使用, 一级缓存, 二级缓存. 如何自定义缓存? 如何默认不开启缓存
dao层的缓存方案 VS 使用spring cahche 实现一致性的缓存 VS 通过编码的方式自定义缓存生成 + 缓存失效. 现在一般使用第二种 和 第三种, 第一种太重。 这三种方案, 如何做最佳实践呢