在test里面比较数字, 用 ==
1 | <if test="mustCityQueryStatus == 1 and city != null and city != ''"> |
在test里面比较数字, 用 ==
1 | <if test="mustCityQueryStatus == 1 and city != null and city != ''"> |
mybatis的一级缓存的生命周期是一个sqlSession
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的一级缓存吗. 答案是不能
在分布式环境下, 建议使用 ehcache 和redis , memacache 做二级缓存
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, namesapce,TypeHanlder, parameterObject,必定是一致的, 其他的参数自然地传入即可。 这样是可以自然命中的。
如果是多个应用, 需要保证namesapce, TypeHanlder, parameterObject的hashCode一致, 需要在代码规范上下工夫, 团队内强制保证一致, 不然很容易保证不一致的情况. 比较理想的办法, 统一多个项目的数据库访问层, 对外提供service输出, 应用不直接访问数据库。 这种情况属于垂直拆分。 一般只有在业务中后期才这样做。
同时, 在使用时, 同样的sql针对不同的服务, 时效性是不一样的. 所以建议cache 默认不生效, 在单个sql上去开启cache. 同样的数据sql如果有cache场景不应可以定义两个id, 对应不同的cache策略
全局开启, 在指定namesapce开启. 这样就可以开启对应namesapce的缓存了. 但是这样会默认所有的sql都走cache, 所以可以在具体的需要强一致性的sql关闭缓存
spring的缓存接口, 和mybatis的缓存区别, 如何使用
jpa的二级缓存
正确的web应用打开方式. entityService + cache. 禁止使用关联查询
关联查询和entityService哪个对数据库的压力大, 各自有什么好处和坏处(好处是entityService可以更准确地cache)
jpa的会话与事务
jpa的缓存原理与使用, 一级缓存, 二级缓存. 如何自定义缓存? 如何默认不开启缓存
dao层的缓存方案 VS 使用spring cahche 实现一致性的缓存 VS 通过编码的方式自定义缓存生成 + 缓存失效. 现在一般使用第二种 和 第三种, 第一种太重。 这三种方案, 如何做最佳实践呢
https://cloud.tencent.com/developer/article/1058172
http://tech.lede.com/2017/06/30/rd/server/loggingHabit/
类内部方法之间的调用不走cache
ehcache cache的对象必须实现了序列化接口
guavaCache CaffeineCache 默认支持每个cahce 细粒度的参数配置, 不同的cache 不同的配置
spring 的 GuavaCacheManager 和 CaffeineCachaManager 是不支持每个cache不同的细粒度参数配置的, 需要重写CacheManager
增加 cacheSpec 和 defaultSpec. cacheSpec是每个cache的配置, defaultSpec是默认的cache配置
1 |
|
重写 createNativeGuavaCache, 以guavaCache 为例, 如果该cache存在配置, 取该cache的配置, 如果没有就取默认配置
1 |
|
然后使用以下配置就可以了, 包名这里涉及到公司信息, 省略不计
1 |
|
也可以使用java bean的配置, 这里不赘述