我正在尝试在由服务方法启动的后台线程中进行一些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无法正常工作:它应该打开一个休眠会话并保持打开状态,直到方法结束。似乎根本没有打开会话。
答案 0 :(得分:0)
这是一篇很好的文章,介绍了多线程在Spring中事务管理的工作方式。这似乎与您的示例非常相似。
重点是您无法启动新的Thread(),因为Transaction
与仅在当前线程中存在的线程局部值相关。
可能您应该在离开有效线程或定义@Async
之前加载惰性引用
@Transactional
服务
https://dzone.com/articles/spring-transaction-management-over-multiple-thread-1