`
liulanghan110
  • 浏览: 1064201 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

mybatis缓存

阅读更多
MyBatis缓存有两种:一级缓存和二级缓存。
 
一级缓存(local cache),即本地缓存,作用域默认为session。当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
本地缓存不能被关闭,可以调用clearCache()来清空本地缓存,或者改变缓存的作用域。
 不能被关闭的原因如下(没看大懂):
By default local cache data is used for the whole session duration. This cache is needed to resolve circular references and to speed up repeated nested queries, so it can never be completely disabled but you can configure the local cache to be used just for the duration of an statement execution by setting localCacheScope=STATEMENT.
 
在SELECT语句中配置刷新缓存,如下:
<select id="aaa" parameterType="string" resultType="integer"  flushCache="true"> 
 
 
在mybatis3.1之后,可以配置本地缓存的作用域。在mybatis.xml中配置,如下:
<setting name="localCacheScope" value="SESSION"/>           作用域为SESSION,这位默认值。
<setting name="localCacheScope" value=" STATEMENT "/>    作用域为STATEMENT,即作用域为SQL。
 
 
二级缓存(second level cache),作用域默认为Mapper(Namespace)。
二级缓存可以被配置为打开或者关闭,默认为关闭,在mybatis.xml中配置。
<setting name="cacheEnabled" value="true"/>
当全局的二级缓存(setting中配置)设置为关闭时可以在Mapper XML中配置单个mapper的二级缓存为打开,配置如下:
<cache />
 
当全局的二级缓存(setting中配置)设置为打开时,mapper中这个配置无效,即mapper中配置为关闭该mapper的二级缓存也是打开。
如果想对某条SQL单独对待,可以在SELECE语句中配置useCache,配置如下:
<select id="aaa" parameterType="string" resultType="integer" useCache="false"> 
 
 
当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
 
当执行一条查询SQL时,
流程为: 从二级缓存中进行查询 -> [如果缓存中没有,委托给 BaseExecutor] -> 进入一级缓存中查询 -> [如果也没有] -> 则执行 JDBC 查询。
 
    例子:
 
 @Transactional
    public void test() {
        System.out.println(depotService.get(252L).getName());
        DepotDto dto = new DepotDto();
        dto.setId(252l);
        dto.setName("test");
        depotService.update(dto);
        System.out.println(depotService.get(252L).getName());
    }
 
输出为:
张江站
test
 
上面的代码test1和test2是一个事务,当执行test1时:
查询站点,保存值到一级缓存(test1),保存值到二级缓存(mapper)。
更新站点的name,刷新一级缓存(test1), 刷新二级缓存(mapper)。
再查询站点,先看二级缓存,没有;再看一级缓存,没有,最后从数据库中查询。所以得出的是数据库中的最新值。
 
 
但当将 depotService.update 方法事务属性配置为REQUIRES_NEW时,相当于有事务test1和事务test2。
输出为:
张江站
张江站
 
 
当执行test1时:
查询站点,保存值到一级缓存(test1),保存值到二级缓存(mapper)。
更新站点的name,刷新一级缓存(test2), 刷新二级缓存(mapper)。此时在test2内部,刷新的是test2的一级缓存,所以
test1的一级缓存还在。
再查询站点,先看二级缓存(mapper),没有;再看一级缓存(test1)(此时在test1事务内部,查找的是test1的一级缓存),
有,则返回值。所以得出的不是数据库中的最新值。
 
如果这时将mapper的get语句配置成这样。
<select id="get" parameterType="java.lang.Long"  resultMap="depotResultMap" flushCache="true"> 
 
输出为:
张江站
test
 
     在mybatis3.1之后,。可以在mybatis.xml中配置得到一样的效果。
 
    最后,强烈推荐阅读http://www.iteye.com/topic/1112327这篇文章。

 另外,个人觉得由于二级缓存作用域是namespace,namespace一般对应一个表,当两个表关联查询时,不知道将SQL放入哪个namespace中。所以配置二级缓存开启的SQL最好是和基础表关联(不常更变的数据)。两个业务表关联的SQL,最好不配置二级缓存开启。

分享到:
评论
12 楼 mos5100 2015-04-23  
634564
11 楼 liulanghan110 2014-04-04  
ForgiDaved 写道
   找到了,读了下源码,发现存入缓存的是一个叫做CacheKey的玩意:debug了下是这个样子的:1236890589:1642688492:yunnex.dgtw.mapper.AnnouncementMapper.getListByParams:0:2147483647:select * from announcement order by send_time desc limit 0 ,11,会把实际生成的sql语句拼接起来,我还以为只是根据查询语句的id来定义key。感谢楼主的谆谆教诲

现在才看到消息。。。确实是你上面说的意思,不过你看了源码了,呵呵
10 楼 ForgiDaved 2014-04-02  
   找到了,读了下源码,发现存入缓存的是一个叫做CacheKey的玩意:debug了下是这个样子的:1236890589:1642688492:yunnex.dgtw.mapper.AnnouncementMapper.getListByParams:0:2147483647:select * from announcement order by send_time desc limit 0 ,11,会把实际生成的sql语句拼接起来,我还以为只是根据查询语句的id来定义key。感谢楼主的谆谆教诲
9 楼 ForgiDaved 2014-04-02  
liulanghan110 写道
ForgiDaved 写道
liulanghan110 写道
ForgiDaved 写道
   楼主对mybatis动态sql下的二级缓存实现有啥思路?

个人觉得由于二级缓存作用域是namespace,namespace一般对应一个表,当两个表关联查询时,不知道将SQL放入哪个namespace中。所以配置二级缓存开启的SQL最好是和基础表关联(不常更变的数据)。两个业务表关联的SQL,最好不配置二级缓存开启。

    可能是我没有表述请求,我所说的动态sql是指sql里面带有if、choose等条件判断的sql的二级缓存


带判断条件的SQL,条件不同SQL不同,查询结果也不同。动态sql可以说是多个普通SQL,会缓存多个结果。你需要如何特殊处理它?

    你的意思是缓存的key是执行的SQL语句么?条件不同生成的执行sql不同,则缓存的key值不同?
8 楼 liulanghan110 2014-04-01  
ForgiDaved 写道
liulanghan110 写道
ForgiDaved 写道
   楼主对mybatis动态sql下的二级缓存实现有啥思路?

个人觉得由于二级缓存作用域是namespace,namespace一般对应一个表,当两个表关联查询时,不知道将SQL放入哪个namespace中。所以配置二级缓存开启的SQL最好是和基础表关联(不常更变的数据)。两个业务表关联的SQL,最好不配置二级缓存开启。

    可能是我没有表述请求,我所说的动态sql是指sql里面带有if、choose等条件判断的sql的二级缓存


带判断条件的SQL,条件不同SQL不同,查询结果也不同。动态sql可以说是多个普通SQL,会缓存多个结果。你需要如何特殊处理它?
7 楼 ForgiDaved 2014-04-01  
liulanghan110 写道
ForgiDaved 写道
   楼主对mybatis动态sql下的二级缓存实现有啥思路?

个人觉得由于二级缓存作用域是namespace,namespace一般对应一个表,当两个表关联查询时,不知道将SQL放入哪个namespace中。所以配置二级缓存开启的SQL最好是和基础表关联(不常更变的数据)。两个业务表关联的SQL,最好不配置二级缓存开启。

    可能是我没有表述请求,我所说的动态sql是指sql里面带有if、choose等条件判断的sql的二级缓存
6 楼 liulanghan110 2014-04-01  
ForgiDaved 写道
   楼主对mybatis动态sql下的二级缓存实现有啥思路?

个人觉得由于二级缓存作用域是namespace,namespace一般对应一个表,当两个表关联查询时,不知道将SQL放入哪个namespace中。所以配置二级缓存开启的SQL最好是和基础表关联(不常更变的数据)。两个业务表关联的SQL,最好不配置二级缓存开启。
5 楼 ForgiDaved 2014-03-31  
   楼主对mybatis动态sql下的二级缓存实现有啥思路?
4 楼 liulanghan110 2014-03-31  
Joeyfihs_1020 写道
请教一下,mybatis的二级缓存是根据namespace来划分cache的域的,也是就必须要在同一个namespace下面的才会在U/C/D之后对select刷新。
如果用mybatis-generator来自动生成mapper文件。在我做的项目中,通常这些生成的文件都没有修改。因为如果改表的话,直接重新生成文件即可,不用考虑merge的问题。
如果有一个select和很多基础表有关的话,如果分配这个select在那一个namespace,或者说有其他的方法可以解决这个这个cache的刷新?


如果该语句和很多表关联,select确实放哪都不好,建议关闭该SQL的二级缓存
3 楼 liulanghan110 2014-03-31  
ForgiDaved 写道
  mybatis的二级缓存默认是关闭的吧。请参考官方网站的doc

对,默认是关闭的
2 楼 ForgiDaved 2014-03-19  
  mybatis的二级缓存默认是关闭的吧。请参考官方网站的doc
1 楼 Joeyfihs_1020 2013-10-18  
请教一下,mybatis的二级缓存是根据namespace来划分cache的域的,也是就必须要在同一个namespace下面的才会在U/C/D之后对select刷新。
如果用mybatis-generator来自动生成mapper文件。在我做的项目中,通常这些生成的文件都没有修改。因为如果改表的话,直接重新生成文件即可,不用考虑merge的问题。
如果有一个select和很多基础表有关的话,如果分配这个select在那一个namespace,或者说有其他的方法可以解决这个这个cache的刷新?

相关推荐

Global site tag (gtag.js) - Google Analytics