....
select A.name, B.detail from A left join B.id = A.id
...
为了解决这个问题,我使用了mybatis的plugin功能,首先拦截Executor class的query方法来得到以下三个参数MappedStatement.class, Object.class, RowBounds.class, 这个三个参数是为了计算存放到cahce中的key,然后再由Executor.createCacheKey(mappedStatement, parameter, rowBounds)方法计算出cacheKey, 这样就可以得到每个select语句被缓存到cahce中时所对应的key, 顺带说一下这个cacheKey的计算是由几个要素来计算的,1.select标签的id, 可通过MappedStatement.getId得到 2. RowBounds 的getOffset()和getLimit() 3. select的sql语句 4. 最重要的一点,也是决定这key是否相同的一点, sql的参数,由上面三个参数中的第二个提供, 当然cahceKey的不同也可能会由RowBounds的不同而不同。
得到cahceKey之后把它保存到一个Map>类型的map里,String对应一个sqlid, 比如上面提到的sql语句 getInfo, 不过还要加上namesapace那就是 A.getInfo, Set 保存某个SQL所对应的不同查询参数的不同结果。当我们得到想要flush的select 的cachekey之后,就可以拦腰Executor class的update方法(包括insert,update,delete), 至于过程很简单,上源码。
在sqlMapConfig.xml中加上:
实现Interceptor接口:
@Intercepts( {
@Signature(type = Executor.class, method = "update", args = {
MappedStatement.class, Object.class }),
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }) })
public class FlushCacheInterceptor implements Interceptor {
private String property;
private Properties properties;
private Map> keyMap = new HashMap>();
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation
.getArgs()[0];
if (!mappedStatement.getConfiguration().isCacheEnabled())
return invocation.proceed();
String sqlId = mappedStatement.getId();
String nameSpace = sqlId.substring(0, sqlId.indexOf('.'));
Executor exe = (Executor) invocation.getTarget();
String methodName = invocation.getMethod().getName();
if (methodName.equals("query")) {
for (Object key : properties.keySet()) {
if (key.equals(sqlId)) {
Object parameter = invocation.getArgs()[1];
RowBounds rowBounds = (RowBounds) invocation.getArgs()[2];
Cache cache = mappedStatement.getConfiguration().getCache(nameSpace);
cache.getReadWriteLock().readLock().lock();
CacheKey cacheKey = exe.createCacheKey(mappedStatement, parameter, rowBounds);
try {
if (cache.getObject(cacheKey) == null) {
if (keyMap.get(sqlId) == null) {
Set cacheSet = new HashSet();
cacheSet.add(cacheKey);
keyMap.put(sqlId, cacheSet);
} else {
keyMap.get(sqlId).add(cacheKey);
}
}
} finally {
cache.getReadWriteLock().readLock().unlock();
}
break;
}
}
} else if (methodName.equals("update")) {
for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) {
String cacheSqlId = (String) e.nextElement();
String updateNameSpace = properties.getProperty(cacheSqlId);
if (updateNameSpace.equals(nameSpace)) {
String cacheNamespace = cacheSqlId.substring(0, cacheSqlId.indexOf('.'));
Cache cache = mappedStatement.getConfiguration().getCache(cacheNamespace);
Set cacheSet = keyMap.get(cacheSqlId);
cache.getReadWriteLock().writeLock().lock();
try {
for (Iterator it = cacheSet.iterator(); it.hasNext();) {
cache.removeObject(it.next());
}
} finally {
cache.getReadWriteLock().writeLock().unlock();
keyMap.remove(cacheSqlId);
}
}
}
}
return invocation.proceed();
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}