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

spring data jpa,根本没法 lazy loading??

  •  
  •   wganbleuthall · 2023-07-31 20:05:11 +08:00 · 1449 次点击
    这是一个创建于 485 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • Postgres:15.3
      • table: accounts, reckoner, 无外键,一条 reckoner 一定能对应一条 accounts 记录
    • spring boot jpa:3.1.0, hibernate:6.2.2.Final
    @Entity
    public class ReckonerEntity {
    
        @OneToOne(cascade = CascadeType.MERGE, fetch = FetchType.LAZY)
        @JoinColumn(name =  "from_acct")
        private AccountsEntity fromAcctEntity;
    }
    
    
    @Entity
    public class AccountsEntity { }
    
    
    public interface ReckonerRepository extends JpaRepository<ReckonerEntity, UUID>, JpaSpecificationExecutor<ReckonerEntity> { }
    
    
    
        @Bean
        @Transactional
        public CommandLineRunner runner() {
            return args -> {
                List<ReckonerEntity> reckoner = reckonerRepository.findAll();
                ReckonerEntity reckonerEntity = reckoner.get(0);
                AccountsEntity fromAcctEntity = reckonerEntity.getFromAcctEntity();
                log.info(fromAcctEntity.getName());
            };
        }
        
    

    运行之后出错:org.hibernate.LazyInitializationException: could not initialize proxy [.....] - no Session 我尝试了 transactional 所有的 propagation 都不行,这明显是懒加载的错误

    解决方案:

    • entityGraph 注解的方式
    • @Query(".. join fetch.. ")的方式
    • 配置 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
    • ...

    但是这所有的解决方案本质上不都是 eager loading 吗??

    • 按照我的理解,上面的代码如果是 lazy loading 应该会 log 两条无 join 的 SQL, 但是我能查到的所有解决方案最终都会导致只生成一条 join 的 SQL

      • 也就是这本质上就是 eager loading
    • 如果自己实现 dao 层, entity 等所有代码不变, 也就是 @PersistenceContext 注入 entityManager 的方式,可以完美的做到 lazy loading ,log 两条 SQL

    • 我就不懂了,所以 spring data jpa 就是不能实现 lazy loading 吗??? 我就想要 lazy loading ,不要 eager loading 有什么办法吗

    5 条回复    2023-08-01 15:57:10 +08:00
    zhzy0077
        1
    zhzy0077  
       2023-07-31 23:42:57 +08:00   ❤️ 1
    https://pastebin.com/t6cNBrU5

    问题在于你在 lazy load 的时候没有把两个 select 放在一个 transaction 里
    KevinBlandy
        2
    KevinBlandy  
       2023-08-01 08:36:14 +08:00
    我是 JPA 重度用户,但是从来不敢用这种 OOP 建模。实在是拿捏不住,太难维护了。

    推荐一个优质的 spring/boot/data/security/cloud 的中文文档,无广告,无须登录,无须关注,在线读。

    https://springdoc.cn/
    qinxi
        3
    qinxi  
       2023-08-01 09:02:07 +08:00
    开启 OpenSessionInView
    wganbleuthall
        4
    wganbleuthall  
    OP
       2023-08-01 13:13:00 +08:00
    @qinxi 不推荐 https://www.baeldung.com/spring-open-session-in-view
    问题找到了已经,很蠢
    @Transactional
    public CommandLineRunner runner() {
    return args -> {
    这种写法 导致 sql 不在同个事务里
    Belmode
        5
    Belmode  
       2023-08-01 15:57:10 +08:00
    @Transactional 的作用没整明白
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4872 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 09:56 · PVG 17:56 · LAX 01:56 · JFK 04:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.