V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lxy
V2EX  ›  Java

被 MyBatis 缓存坑了,各位可以来了解下

  •  
  •   lxy · 2020-06-11 11:39:27 +08:00 · 3352 次点击
    这是一个创建于 1407 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Debug 了半天。

    SpringBoot + MyBatis,默认配置,你觉得下述代码可能有何问题?

    @Transactional
    public void some_service(List<Person> persons) {
        for (Person person : persons) {
            List<Card> cards = dao.findByCardIds(person.getCardIds());
            do_something(cards);
        }
    }
    

    注意 MyBatis 有缓存机制,在同一 SqlSession 中默认开启,每次非事务查询用的都是新建的 SqlSession,所以缓存不生效。

    但当开启事务时,spring 会使用同一个 SqlSession 做查询,此情况下一级缓存生效。

    例子中,如果程序对查询结果 list 进行了修改操作,那么缓存中的 list 也会相应变化。

    第二次查询时若参数相同(比如 for 循环的是两个相同的 person ),会将缓存中的已被修改过的 list 取出。

    取出的污染数据可能导致后续代码流程错误。

    解决方法是在 Mapper 设置 flushCache="true"。

    总结一下设计缺陷:

    1. 默认配置下,缓存表现不一致。如果非事务查询无缓存,那么事务性查询也应该无缓存。

    2. 缓存未做读取时拷贝( copy on read )。由于缓存返回的是结果集的引用,如果后续代码修改了结果集,将导致缓存污染。

    12 条回复    2020-06-11 18:14:58 +08:00
    cubecube
        1
    cubecube  
       2020-06-11 11:52:26 +08:00 via Android
    这不叫被坑,这叫没搞清楚机制,系统出了 bug
    wysnylc
        2
    wysnylc  
       2020-06-11 11:53:42 +08:00
    xuanbg
        3
    xuanbg  
       2020-06-11 11:54:36 +08:00
    查询瞎用什么事务……
    PopRain
        4
    PopRain  
       2020-06-11 12:08:50 +08:00
    事务里面,难道不应别人不能修改,用缓存的没有错。。。。 不要乱开事务
    lxy
        5
    lxy  
    OP
       2020-06-11 12:09:49 +08:00
    @cubecube 这是设计有坑

    @wysnylc 我说的是一级缓存,默认开启的

    @xuanbg 只是举个例子,不是实际情况
    luckyrayyy
        6
    luckyrayyy  
       2020-06-11 12:30:05 +08:00
    这是设计特性,不是 bug 啊...
    aragakiyuii
        7
    aragakiyuii  
       2020-06-11 12:46:04 +08:00 via Android
    这不是设计缺陷
    如果业务上 cardId 会重复的话应该在循环外面把 cardId 取出来放到 set 里,再去循环 cardId set
    DJQTDJ
        8
    DJQTDJ  
       2020-06-11 13:22:09 +08:00
    如果是 bug 的话,就不会公开 flushCache="true"的方法了
    dayformyjob
        9
    dayformyjob  
       2020-06-11 14:09:56 +08:00
    每次查询用最新的,flushCache="true",或者 useCache="false"
    YoRuo
        10
    YoRuo  
       2020-06-11 17:45:06 +08:00
    不是 bug 。。。。
    BBCCBB
        11
    BBCCBB  
       2020-06-11 18:13:04 +08:00
    是 feature
    BBCCBB
        12
    BBCCBB  
       2020-06-11 18:14:58 +08:00
    在高级别的事务隔离级别下, 是有可重复读的特性的, mybatis 事务缓存了同样的查询
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1216 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 23:23 · PVG 07:23 · LAX 16:23 · JFK 19:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.