Spring @Transactional 上的 Hibernate LazyInitializationException
Spring Hibernate LazyInitializationException on @Transactional
我有一个在启动时以递归方式运行异步任务的服务:
@Service
public class TaskService {
private final TaskRepository taskRepository;
@Inject
public TaskService(TaskRepository taskRepository) {
this.taskRepository= taskRepository;
}
private final int currentTaskId = -1;
@Transactional
@PostConstruct
private void init() {
taskRepository.findByClosedDateIsNull().forEach(taskRepository::delete);
runTask();
}
@Async
@Transactional
private void runTask() {
if (!getCurrent().isPresent()) {
Task task = new Task();
//set props
currentTaskId = taskRepository.save(task).getId();
}
Util.sleep(5000); //wrapper for simple Thread.sleep(long l).
Task task = getCurrent().get();
if (task.getEvents().size > 0) {
//bussiness logic
Util.sleep(1000);
}
runTask();
}
@Transactional(readOnly = true)
private Optional<Task> getCurrent() {
return taskRepository.findOneById(currentTaskId).map(task -> {
task.getEvents().size(); //throws the error here
return task;
});
}
}
堆栈跟踪:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.domain.Task.events, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:156)
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:160)
at com.test.service.TaskService.lambda$getCurrent(TaskService.java:135)
at java.util.Optional.map(Optional.java:215)
at com.test.service.TaskService.getCurrent(TaskService.java:134)
at com.test.service.TaskService.runTask(TaskService.java:163)
at com.test.service.TaskService.init(TaskService.java:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:310)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 21 common frames omitted
我也试过Hibernate.initialize(对象代理);。 OpenViewSessionFilter 不是我的解决方案。我不想设置这个集合 EAGER。
我找到了解决方案(不知道这是否是一种不好的做法,但它对我有用)。只需在 JpaRepository 中创建一个默认方法并用 @Transactional 注释它。在服务中调用此方法。
对我来说,当我在第一个函数调用中删除 @Transactional
(在你的情况下是 init()
)并将 @Async
功能移动到一个单独的功能时,它解决了这个问题豆.
我有一个在启动时以递归方式运行异步任务的服务:
@Service
public class TaskService {
private final TaskRepository taskRepository;
@Inject
public TaskService(TaskRepository taskRepository) {
this.taskRepository= taskRepository;
}
private final int currentTaskId = -1;
@Transactional
@PostConstruct
private void init() {
taskRepository.findByClosedDateIsNull().forEach(taskRepository::delete);
runTask();
}
@Async
@Transactional
private void runTask() {
if (!getCurrent().isPresent()) {
Task task = new Task();
//set props
currentTaskId = taskRepository.save(task).getId();
}
Util.sleep(5000); //wrapper for simple Thread.sleep(long l).
Task task = getCurrent().get();
if (task.getEvents().size > 0) {
//bussiness logic
Util.sleep(1000);
}
runTask();
}
@Transactional(readOnly = true)
private Optional<Task> getCurrent() {
return taskRepository.findOneById(currentTaskId).map(task -> {
task.getEvents().size(); //throws the error here
return task;
});
}
}
堆栈跟踪:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.test.domain.Task.events, could not initialize proxy - no Session at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215) at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:156) at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:160) at com.test.service.TaskService.lambda$getCurrent(TaskService.java:135) at java.util.Optional.map(Optional.java:215) at com.test.service.TaskService.getCurrent(TaskService.java:134) at com.test.service.TaskService.runTask(TaskService.java:163) at com.test.service.TaskService.init(TaskService.java:66) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:310) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133) ... 21 common frames omitted
我也试过Hibernate.initialize(对象代理);。 OpenViewSessionFilter 不是我的解决方案。我不想设置这个集合 EAGER。
我找到了解决方案(不知道这是否是一种不好的做法,但它对我有用)。只需在 JpaRepository 中创建一个默认方法并用 @Transactional 注释它。在服务中调用此方法。
对我来说,当我在第一个函数调用中删除 @Transactional
(在你的情况下是 init()
)并将 @Async
功能移动到一个单独的功能时,它解决了这个问题豆.