一、缓存
我们知道,在Mybatis中是有缓存实现的。分一级缓存和二级缓存,不过一级缓存其实没啥用。因为我们知道它是基于sqlSession的,而sqlSession在每一次的方法执行时都会被新创建。二级缓存是基于namespace,离开了它也是不行。有没有一种方式来提供自定义的缓存机制呢?
1、Executor
Executor是Mybatis中的执行器。所有的查询就是调用它的 <E>List<E>query()
方法。我们就可以在这里进行拦截,不让它执行后面的查询动作, 直接从缓存返回。
在这个类里面,我们先获取参数中的缓存标记和缓存的Key,去查询Redis。如果命中,则返回;未命中,接着执行它本身的方法。
@Intercepts({@Signature(method = "query", type = Executor.class,args = {
MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})
//BeanFactoryAware是Spring中的接口。目的是获取jedisService的Bean
public class ExecutorInterceptor implements Interceptor,BeanFactoryAware{
private JedisServiceImpl jedisService;
@SuppressWarnings("unchecked")
public Object intercept(Invocation invocation) throws Throwable {
if (invocation.getTarget() instanceof CachingExecutor) {
//获取CachingExecutor所有的参数
Object[] params = invocation.getArgs();
//第二个参数就是业务方法的参数
Map<String,Object> paramMap = (Map<String, Object>) params[1];
String isCache = paramMap.get("isCache").toString();
//判断是否需要缓存,并取到缓存的Key去查询Redis
if (isCache!=null && "true".equals(isCache)) {
String cacheKey = paramMap.get("cacheKey").toString();
String cacheResult = jedisService.getString(cacheKey);
if (cacheResult!=null) {
System.out.println("已命中Redis缓存,直接返回.");
return JSON.parseObject(cacheResult, new TypeReference<List<Object>>(){});
}else {
return invocation.proceed();
}
}
}
return invocation.proceed();
}
//返回代理对象
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
}
return target;
}
public void setProperties(Properties properties) {}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
jedisService = (JedisServiceImpl) beanFactory.getBean("jedisServiceImpl");
}
}
以上方法只是从缓存中获取数据,但什么时候往缓存中添加数据呢?总不能在每个业务方法里面调用Redis的方法,以后如果把Redis换成了别的数据库,岂不是很尴尬。
回忆一下Mybatis执行方法的整个流程。在提交执行完SQL之后,它是怎么获取返回值的呢?
2、ResultSetHandler
没有印象吗?就是这句 returnresultSetHandler.<E>handleResultSets(ps);
其中的resultSetHandler就是DefaultResultSetHandle