后台线程中的休眠会话始终处于关闭状态,从而导致LazyInitializationException

时间:2018-10-04 11:16:01

标签: hibernate groovy spring-data-jpa

我正在尝试在由服务方法启动的后台线程中进行一些JPA阅读,计算然后保存的工作。我使用该服务的单个@Transactional方法来完成所有工作。该服务中的其他方法将启动处理它的线程。但是,如果我尝试访问一个懒惰的@oneToMany关系,即使我在第一次检索结果后立即执行了此操作,也会收到LazyInitializationException-没有会话。怎么没有会议?我只在一行之前检索了结果。

请忽略此处未使用线程池。这段代码是用groovy编写的,因此对于纯Java开发人员来说可能很难理解。

@Service
public class NotifierService {
public void startNewNotifierThread() {
    stopNotifierThreadIfRunning()
    log.info "Starting notifier thread"

    notifierThread = new Thread({
        while(!Thread.interrupted()) {
            runNotifier()
            Thread.sleep(10000)
        }

        if(Thread.interrupted()) {
            log.info("Reached end of thread due to interrupt")
        }
    })

    notifierThread.start()
}

@Transactional public void runNotifier() {
    boolean isAlive0 = TransactionSynchronizationManager.isActualTransactionActive()
    Session session = (Session) entityManager.getDelegate();
    Collection<User> allSubscribedUsers = userRepository.getAllSubscribedUsers()

    log.debug "Processing subscriptions for ${allSubscribedUsers.size()} subscribed users"

    int fcmMsgsSent = 0, apnMsgsSent = 0
    boolean isAlive1 = TransactionSynchronizationManager.isActualTransactionActive()

    allSubscribedUsers.each { User user ->
        boolean isAlive2 = TransactionSynchronizationManager.isActualTransactionActive()
        log.debug "Subscriptions for user ${user.email}: ${user.analysisSubscriptions.size()}"

        Set<AnalysisSubscription> updatedSubscriptions = new HashSet<AnalysisSubscription>()

        user.analysisSubscriptions.each { AnalysisSubscription subscription ->
            boolean isAlive3 = TransactionSynchronizationManager.isActualTransactionActive()

            int numResults = subscription.analysisResults.size() //LAZYINITIALIZATIONEXCEPTION
        }
    }
}

此代码的结果是isAlive0,isAlive1,isAlive2,isAlive3均为false。 session.closed的值即使在方法开始时也为true,这并不说明为什么它能够检索所有订阅的用户(我使用下面的存储库-这使我怀疑该方法正在使用自己的会话... ?)。似乎@Transactional无法正常工作:它应该打开一个休眠会话并保持打开状态,直到方法结束。似乎根本没有打开会话。

1 个答案:

答案 0 :(得分:0)

这是一篇很好的文章,介绍了多线程在Spring中事务管理的工作方式。这似乎与您的示例非常相似。

重点是您无法启动新的Thread(),因为Transaction与仅在当前线程中存在的线程局部值相关。

可能您应该在离开有效线程或定义@Async之前加载惰性引用  @Transactional服务

https://dzone.com/articles/spring-transaction-management-over-multiple-thread-1