ibatis 缓存导致的一个问题

来源:互联网 发布:国际贸易数据 编辑:程序博客网 时间:2024/05/02 02:03

最近由于业务的需要(系统对数据的操作用的是mybatis),需要对数据库中的某些字段进行加密。为了保证对外层应用的透明性,对SqlSessionTemplate 的部分方法进行了重写.一般对inser update 的时候,对插入的部分列加密,对select 的时候对加密的字段进行解密

如对update方法重写如下

 @Override    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {        // TODO Auto-generated method stub        return (List<E>) returnDeCryption(statement, super.selectList(statement, parameter, rowBounds));    }


其中returnDeCryption方法是自己写的解密方法。

开始用的时候都加密解密的时候很正常。但是有时候操作在做解密的时候,解密失败。

通过分析,是在一个功能中,对同一个select 方法调用两次的时候解密失败.通过分析,原来是mybatis 的缓存导致的。

具体分析如下:

mybatis中有一个缓存类

public class PerpetualCache implements Cache {  private String id;//缓存key value 数据的map 对象  private Map<Object, Object> cache = new HashMap<Object, Object>();


真正使用缓存的对象在下边类中,

public abstract class BaseExecutor implements Executor {  private static final Log log = LogFactory.getLog(BaseExecutor.class);  protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;//缓存  protected PerpetualCache localCache;//缓存  protected PerpetualCache localOutputParameterCache;  protected Configuration configuration;


在这个类中声明了两个属性

localCache 缓存查询的结果
<pre name="code" class="java">localOutputParameterCache 缓存执行的参数


//清楚缓存public void clearLocalCache() {    if (!closed) {      localCache.clear();      localOutputParameterCache.clear();    }  }

//update 数据的时候会调用clearLocalCache方法清楚缓存,这样保证update 后,如果调用同一个select 查询到的是最新的结果public int update(MappedStatement ms, Object parameter) throws SQLException {    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());    if (closed) throw new ExecutorException("Executor was closed.");    clearLocalCache();    return doUpdate(ms, parameter);  }


//查询的时候,如果是同一条sql 并且是同样的参数,就会把查询结果以及查询语句放到缓存中private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {    List<E> list;    localCache.putObject(key, EXECUTION_PLACEHOLDER);    try {      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);    } finally {      localCache.removeObject(key);    }    localCache.putObject(key, list);    if (ms.getStatementType() == StatementType.CALLABLE) {      localOutputParameterCache.putObject(key, parameter);    }    return list;  }


通过查看BaseExecutor的源码,对导致问题的原因一目了然了。

1:mybatis 对同一个select (执行sql以及对应的sql参数的值都一样时才是同一次select),执行多次时,只有第一次去查询数据库,后续的查询是直接从缓存中把结果取出

2:由于重写了selectList方法,对每次查询的结果都进行解密,但是实际上第一次查询时就对结果进行了解密,此时mybatis 已经是缓存的明文数据,当第二查询的时候,查询到的已经是明文数据,所以解密出错。








0 0
原创粉丝点击