ibatis 缓存导致的一个问题

最近由于业务的需要(系统对数据的操作用的是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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值