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

JPA 二级缓存问题请教

  •  
  •   NULL2020 · 2020-08-27 10:20:58 +08:00 · 1928 次点击
    这是一个创建于 1558 天前的主题,其中的信息可能已经有所发展或是发生改变。

    service 层两个查询方法:

        @Cacheable(value = "space", key = "#id", unless = "#result==null")
        public Space searchOne(long id) {
            return repository.findById(id).orElse(null);
        }
    
        public Space searchOneWithUser(long id) {
            Space space = searchOne(id);
            space.setCreator(userService.searchOne(space.getUserId()));
            return space;
        }
    
    

    为什么调用第二个方法不走缓存? 缓存有数据还是从数据库里查,缓存没有数据,查出来后也不写到缓存里面。

    11 条回复    2020-08-27 19:15:56 +08:00
    CoderGeek
        1
    CoderGeek  
       2020-08-27 10:30:01 +08:00   ❤️ 2
    这个是基于 AOP 的动态代理实现,你内部引用不生效
    1.放到外部的类调用
    2.用 ApplicationContext.getBean 在调用 searchOne(id)
    wysnylc
        2
    wysnylc  
       2020-08-27 10:38:52 +08:00   ❤️ 2
    https://www.jianshu.com/p/6534945eb3b5
    JDK Dynamic Proxy 无法拦截 this,Spring 默认使用 JDK Dynamic Proxy,所以 Spring AOP 无法代理 this 所以 Spring Cache 缓存注解无效.解决方案为注入当前类的 bean 进行使用(但是有可能造成循环调用)或者拆分逻辑到另一个 services
    题外话:你这不是 JPA 二级缓存而是 Spring Cache 自定义缓存,二级缓存是基于表的缓存
    NULL2020
        3
    NULL2020  
    OP
       2020-08-27 10:42:55 +08:00
    @CoderGeek #1
    @wysnylc #2

    多谢多谢
    ixx
        4
    ixx  
       2020-08-27 10:49:17 +08:00
    多说一句,有一道关于事务的面试题就是你这么写的,把缓存注解换成事务注解 原理是一样的 ,调用第二个不走事务
    NULL2020
        5
    NULL2020  
    OP
       2020-08-27 10:51:32 +08:00
    @wysnylc #2 我的理解,二级缓存就是查询缓存,你说的 [基于表的缓存] 好像第一次听说,有没有技术文章可以分享一下?
    NULL2020
        6
    NULL2020  
    OP
       2020-08-27 10:52:33 +08:00
    @ixx #4 感谢,事务失效的几种原因之一 [自调用]
    aragakiyuii
        7
    aragakiyuii  
       2020-08-27 10:52:42 +08:00
    这个不是 orm 的二级缓存吧。。
    cglib 代理完大概就这样(不准确

    aragakiyuii
        8
    aragakiyuii  
       2020-08-27 10:57:04 +08:00
    @aragakiyuii #7 extend -> extends
    leafre
        10
    leafre  
       2020-08-27 15:21:25 +08:00
    Space space = this.searchOne(id);
    <aop:aspectj-autoproxy expose-proxy="true"/>
    br00k
        11
    br00k  
       2020-08-27 19:15:56 +08:00
    把当前实例使用 @Lazy 注入,内部方法走 service 调用就可以走代理了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3157 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:50 · PVG 21:50 · LAX 05:50 · JFK 08:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.