mybatis 学习五 二级缓存不推荐使用

mybatis 二级缓存不推荐使用

    一 mybatis 的缓存使用。

大体就是首先根据你的 sqlid,参数的信息自己算出一个 key 值,然后你查询的时候,会先把这个 key 值去缓存中找看有没有 value,如果有,直接返回出来,就不查询 db 了。如果没有,那么查询 db,然后将 key,value 保存到缓存中,以便下次使用。

     1.1mybatis 的一级缓存是基于 sqlsession 为生命周期的

当你这个 session 没有了,缓存就没有了,其次当你 sql 执行!isselect 语句的时候,缓存也会被直接全部清理掉以保证数据一致性。
  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);
  }

 

     1.2 mybatis 的二级缓存是基于 application 为生命周期的

范围是按照每个 namepace 一个缓存来存贮和维护,同一个 namespace 放到一个缓存对象中,当这个 namaspace 中执行了!isselect 语句的时候,整个 namespace 中的缓存全部清除掉。
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
     //清理缓存,并且!isselect 语句的 flushcache 都是默认为 true 的。
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }

 

 
以下摘抄自网络观点文字  http://blog.csdn.net/isea533/article/details/44566257

     三、Cache 使用时的注意事项


1. 只能在【只有单表操作】的表上使用缓存
不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个 namespace 下。
2. 在可以保证查询远远大于 insert,update,delete 操作的情况下使用缓存
这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在 1 的前提下才可以!

四、避免使用二级缓存


可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。
insert,update,delete 操作会清空所在 namespace 下的全部缓存。
通常使用 MyBatis Generator 生成的代码中,都是各个表独立的,每个表都有自己的 namespace。
为什么避免使用二级缓存
在符合【Cache 使用时的注意事项】的要求时,并没有什么危害。
其他情况就会有很多危害了。
针对一个表的某些操作不在他独立的 namespace 下进行。
例如在 UserMapper.xml 中有大多数针对 user 表的操作。但是在一个 XXXMapper.xml 中,还有针对 user 单表的操作。
这会导致 user 在两个命名空间下的数据不一致。如果在 UserMapper.xml 中做了刷新缓存的操作,在 XXXMapper.xml 中缓存仍然有效,如果有针对 user 的单表查询,使用缓存的结果可能会不正确。
更危险的情况是在 XXXMapper.xml 做了 insert,update,delete 操作时,会导致 UserMapper.xml 中的各种操作充满未知和风险。
有关这样单表的操作可能不常见。但是你也许想到了一种常见的情况。
多表操作一定不能使用缓存
为什么不能?
首先不管多表操作写到那个 namespace 下,都会存在某个表不在这个 namespace 下的情况。
例如两个表:role 和 user_role,如果我想查询出某个用户的全部角色 role,就一定会涉及到多表的操作。
<select id="selectUserRoles" resultType="UserRoleVO">
    select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}
</select>

 

像上面这个查询,你会写到那个 xml 中呢??
不管是写到 RoleMapper.xml 还是 UserRoleMapper.xml,或者是一个独立的 XxxMapper.xml 中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。
如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。
这点应该很容易理解。
在我看来,就以 MyBatis 目前的缓存方式来看是无解的。多表操作根本不能缓存。
如果你让他们都使用同一个 namespace(通过 <cache-ref>)来避免脏数据,那就失去了缓存的意义。
看到这里,实际上就是说,二级缓存不能用。整篇文章介绍这么多也没什么用了。

五、挽救二级缓存?


想更高效率的使用二级缓存是解决不了了。
但是解决多表操作避免脏数据还是有法解决的。解决思路就是通过拦截器判断执行的 sql 涉及到那些表(可以用 jsqlparser 解析),然后把相关表的缓存自动清空。但是这种方式对缓存的使用效率是很低的。
设计这样一个插件是相当复杂的,既然我没想着去实现,就不废话了。
最后还是建议,放弃二级缓存,在业务层使用可控制的缓存代替更好。