无法在@Transactional方法内部初始化延迟加载的关系

时间:2019-04-11 19:53:07

标签: spring hibernate

我有一组像这样的简单模型(为简便起见,省略了getter和setter方法):

@Entity
public class Customer {
  @Id 
  private Integer id;
}

@Entity
public class Order {
  @Id
  private Integer id;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "customer_id")
  private Customer customer;
}

我正在尝试使用带有findById方法的Spring JPA存储库(包括客户)加载订单。

首先,我尝试了这一点:

@Transactional
Optional<Order> findById(Integer id) {
    return repository.findById(id);
}

但是当我尝试访问Customer时,我遇到了LazyInitializationException:无法初始化代理-没有会话。因此,在引用some other questions之后,我将方法更新为较丑陋,但显式调用了Hibernate.initialize

@Transactional
Optional<Order> findById(Integer id) {
    return repository.findById(id)
                     .map( order -> {
                         Hibernate.initialize(order.getCustomer());
                         return order;
                     );
}

但是我仍然得到org.hibernate.LazyInitializationException: could not initialize proxy - no Sessionrepository是常规的CrudRepository,提供了现成的findById方法。

如何初始化这个延迟加载的子实体?我的理解是,@Transactional表示对于整个此方法调用,我仍应处于事务范围之内。下游唯一的事情是存储库本身,它只是一个接口,因此我不确定如何进一步强制此子实体的加载。

可以从数据库中正确检索Order实体及其中的所有其他内容;只有当我尝试获取延迟加载的子实体时,我们才开始出现问题。

我设法做到这一点的唯一方法是使用left join fetch在存储库中编写一个custom hql method。在这种方法有效的同时,它使我的存储库变得混乱,该方法几乎是另一个方法的重复,而且我敢肯定我实际上并不需要该方法(因此,我宁愿不这样做)。

Spring-Boot 2.1.4.RELEASE,Spring 5.1.6.RELEASE,Hibernate 5.3.7.Final。

1 个答案:

答案 0 :(得分:0)

您必须将方法定义为@Transactional public Optional<Order> findById(Integer id) { Optional<Order> order = repository.findById(id); order.ifPresent(o -> Hibernate.initialize(o.getCustomer())); return order; } 。请参见spring docs中的“方法可见性和@Transactional”。

这应该有效:

autoload -Uz compinit && compinit