【问题标题】:JPA / Hibernate Spring @Transactional vs. JOIN FETCHJPA / Hibernate Spring @Transactional 与 JOIN FETCH
【发布时间】:2020-03-03 19:11:45
【问题描述】:

我正面临 LazyInitializationException 的有趣解决方案。 为了防止这种情况(在 OneToMany 或 ManyToMany 上),一种已知的解决方案是使用 JOIN FETCH Query。 你可以看到她的几个例子之一:https://thoughts-on-java.org/best-practices-for-many-to-many-associations-with-hibernate-and-jpa/

其他更简单的解决方案是使用 Spring 中的 @Transactional。 比如这样:

@DeleteMapping(value ="/product/{tagId}")
    @ResponseBody
    @Transactional
    public String deleteProductWithoutRelation(@PathVariable String product, Model model) {     
        Optional<Product> pr = productService.selectProduct(product);
        if (pr.isPresent()) {
            tag.get().getCustomer().size(); //usualy throws LazyInitializationException, 
                                            //without JOIN-FETCH Statment or @Transactional
        return deletedTagId;    
    }

当然,您可以将存储库服务中的某些方法的@Transactional 放置在此解决方案中。 那么这两种解决方案有哪些优点或缺点呢?

【问题讨论】:

标签: java spring hibernate jpa lazy-initialization


【解决方案1】:

我们需要在这里解开一些事情。

  1. @Transactional 意味着 Spring 确保打开一个数据库连接(+ 事务)并再次关闭它。就是这样。
  2. 当您选择一个包含惰性字段的实体时,您实际上是在说:我正在从我的实体中选择“一些”字段,除了惰性字段。
  3. 但是,如果您稍后需要该惰性字段,因为您试图在视图(.html、.ftl、.jsp 等)中访问它,您需要向数据库发出另一个选择以获取它。
  4. 问题:此时,如果您在@Transactional 方法之外,则您不再打开数据库连接,因此会出现 LazyInitException。
  5. 总结一下:您的 fetch 确保为所有数据发出 1 个选择。如果你不这样做,你需要一个开放的数据库连接/事务,@Transactional 给你。

建议:您应该尝试获取渲染视图所需的所有数据,并使用适当的 JPQL/Criteria/SQL 语句,而不是过度依赖重新选择惰性字段。

【讨论】:

  • 谢谢。作为回复,我仔细检查了休眠查询并看到,@Transactional 为惰性字段再执行一个查询。使用适当的 join-fetch 查询,您只有一个查询。
猜你喜欢
  • 2021-12-19
  • 2012-08-31
  • 2017-08-21
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 1970-01-01
  • 2019-06-16
  • 2013-06-30
相关资源
最近更新 更多