@Transactional上的Spring Hibernate LazyInitializationException

时间:2016-10-13 21:14:14

标签: java spring hibernate spring-data spring-transactions

我有一个在启动时运行异步任务的服务,它以递归方式运行:

@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;
        });
    }

}

堆栈跟踪:

  

引起:org.hibernate.LazyInitializationException:懒得初始化一个角色集合:com.test.domain.Task.events,无法初始化代理 - 没有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 $ 5(TaskService.java:135)       在java.util.Optional.map(Optional.java:215)       在com.test.service.TaskService.getCurrent(TaskService.java:134)       在com.test.service.TaskService.runTask(TaskService.java:163)       在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个常见帧

我也尝试过Hibernate.initialize(Object proxy);. OpenViewSessionFilter对我来说不是解决方案。我不想将此集合设置为EAGER。

2 个答案:

答案 0 :(得分:0)

我找到了一个解决方案(不知道这是不好的做法,但它对我有用)。只需在JpaRepository中创建一个默认方法,然后使用@Transactional对其进行注释。在服务中调用此方法。

答案 1 :(得分:0)

对我来说,当我在第一个函数调用中删除 @Transactional(在您的情况下这将是 init())并将 @Async 功能移动到一个单独的 bean 时,它解决了这个问题。