【问题标题】:Spring boot @Async annotation throw LazyInitializationExceptionSpring boot @Async 注解抛出 LazyInitializationException
【发布时间】:2018-09-26 13:43:10
【问题描述】:

我有一个 emailsenderservice 来异步管理电子邮件通知。 有 2 种异步方法,一种方法有效,另一种方法抛出 LazyInitializationException:

@Service
public class EmailSenderService {
    // working
    @Async
    public void sendNewBidRequestEmail(BidRequest bidRequest) {
        this.sendNewBidRequestEmailToSupplier(bidRequest);
    }
    @Transactional
    public void sendNewBidRequestEmailToSupplier(BidRequest bidRequest) {
        sendNewBidRequestEmailToSupplier(bidRequest, bidRequest.getHotels());
    }

    @Transactional
    public void sendNewBidRequestEmailToSupplier(BidRequest bidRequest, List<Hotel> hotelList) {
        for (Hotel hotel : hotelList) {
           ...
           this.sender.send()
        }
    }


    // not working, throw exception
    @Async
    public void sendCancelledBidRequestEmail(BidRequest bidRequest, String reason) {
        this.sendCancelledBidRequestEmailToSupplier(bidRequest, bidRequest.getHotels(), reason);
    }

    @Transactional
    public void sendCancelledBidRequestEmailToSupplier(BidRequest bidRequest, List<Hotel> hotelList, String reason) {
        for (Hotel hotel : hotelList) {   // throw exception here
           ...
           this.sender.send();
        }
}

我完全关注this thread。 您可以看到两个异步方法具有几乎相同的结构。异步方法调用事务方法。但是第二个抛出org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.corpobids.server.entity.BidRequest.hotels, could not initialize proxy - no Session

我什至模仿第一个异步方法结构将第二个修改为:

@Async
    public void sendCancelledBidRequestEmail(BidRequest bidRequest, String reason) {
        this.sendCancelledBidRequestEmailToSupplier(bidRequest, reason);
    }

    @Transactional
    public void sendCancelledBidRequestEmailToSupplier(BidRequest bidRequest, String reason) {
        this.sendCancelledBidRequestEmailToSupplier(bidRequest, bidRequest.getHotels(), reason);
    }

    @Transactional
    public void sendCancelledBidRequestEmailToSupplier(BidRequest bidRequest, List<Hotel> hotelList, String reason) {
        for (Hotel hotel : hotelList) {   // exception in this line
               ...
               this.sender.send();
            }
    }
}

这一次,它给了我java.lang.IllegalStateException: org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl@fce9b7b is closed

我想知道我的代码中的缺失点,任何帮助将不胜感激。

【问题讨论】:

    标签: java spring hibernate


    【解决方案1】:

    您对 JPA 有疑问。

    在 JPA 中,OneToMany 关系有两种行为 LAZY 和 EAGER。

    你可以查看一个很好的解释:Difference between FetchType LAZY and EAGER in Java Persistence API?

    我假设当您在异步模式下调用代码时,JPA 的上下文是松散的。因此,由于上下文不同,Hibernate 无法填充执行新查询的关系。为了解决您的问题,您有两种选择:

    1. 配置与 EAGER 的关系
    2. 在调用异步方法之前预加载关系

    使用延迟加载更好的潜在客户技术:

    https://www.thoughts-on-java.org/5-ways-to-initialize-lazy-relations-and-when-to-use-them/

    【讨论】:

    • 我有 2 种 aync 方法,一种有效,另一种无效,我找不到它们之间的任何区别。
    • 我会假设酒店列表是在调用 sendNew 之前预加载的,并且在调用 cancel 方法之前没有加载
    • 我可以知道如何预加载关系吗?
    • 在调用异步方法之前调用酒店。即 bidRequest.hotels.size() 这将强制 JPA 查询酒店关系
    • 我添加了延迟加载最佳实践的链接
    猜你喜欢
    • 2018-04-03
    • 2019-05-19
    • 2021-02-19
    • 2018-08-11
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多