Java Spring@Async:惰性集合上的null hibernate会话
我正在服务层方法上使用Java Spring@Async:惰性集合上的null hibernate会话,java,spring,hibernate,hibernate-session,Java,Spring,Hibernate,Hibernate Session,我正在服务层方法上使用@Async注释 当我急切地加载@OneToMany集合字段时,一切正常,但当我尝试访问延迟加载的元素时,我发现HibernateSessionImplementorobjectsession为空。这显然给了我一个例外: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: .... 这是我的收藏栏: @OneToMany(mappe
@Async
注释
当我急切地加载@OneToMany集合字段时,一切正常,但当我尝试访问延迟加载的元素时,我发现HibernateSessionImplementor
objectsession
为空。这显然给了我一个例外:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
....
这是我的收藏栏:
@OneToMany(mappedBy="abc", fetch=FetchType.LAZY, cascade=CascadeType.REMOVE)
@OrderBy(value="xsd asc")
@JsonIgnore
private Set<Item> items = new HashSet<Item>();
Spring的事务上下文是使用保存的。这意味着您的SessionFactory仅对发送请求的线程可用,因此,如果您创建一个新线程,您将得到一个
null
和一个相应的异常
您的@Async
方法所做的是在另一个线程中使用来运行您的方法。因此,上述问题发生在您的服务中
我引用《春天》的文件:
针对单个JPA的PlatformTransactionManager实现
实体管理工厂从指定的服务器绑定JPA EntityManager
工厂到线程,可能允许一个线程绑定
每个工厂的实体经理。共享身份管理器创建者和
@PersistenceContext知道线程绑定的实体管理器和
自动参与此类交易。使用其中一个是
支持此事务管理的JPA访问代码需要
机制
如果你想保留你的注释,那么你应该看看Hibernate,然后自己管理会话
有关更多信息,请参阅。在正常情况下(没有@Async
),事务通过调用层次结构从一个Spring组件传播到另一个组件
当@Transactional
Spring@Component
调用带有@Async
注释的方法时,不会发生这种情况。异步方法的调用由任务执行者在稍后时间进行调度和执行,因此作为“新鲜”调用处理,即没有事务上下文。如果@Async
方法(或声明它的组件)本身不是@Transactional
,Spring将不会管理任何需要的事务
尝试注释调用
@Async
方法的方法,并告诉我们是否有效。我也有同样的问题,花了几天时间试图找到解决方案,最后终于找到了解决方案。我想分享我为那些可能有同样问题的人找到的细节
1-您的@Async
-带注释的方法应该在单独的bean中声明,而不是@Controller
-或@RestController
-带注释的bean中声明
第二,您当然需要声明方法@Transactional
,该方法是从@Async
声明的方法中调用的。但是,从@Async
方法调用的第一个方法必须定义为@Transactional
。我在方法执行堆栈的第二级或第三级使用了@Transactional
方法,因此问题没有得到解决,我花了两天时间试图弄清楚到底发生了什么
所以最好的办法就是
@Controller
ControllerBean {
@Autowired
AsyncService asyncService;
public controllerMethod() {
asyncService.asyncMethod();
}
}
@Service
AsyncService {
@Autowired
TransactionalService transactionalService;
@Async
public asyncMethod() {
transactionalService.transactionalMethod();
}
}
@Service
TransactionalService {
@Autowired
SomeOtherService someOtherService;
@Autowired
EntityRepository entityRepository;
@Transactional
public transactionalMethod() {
Entity entity = entityRepository.findOne(12345);
someOtherService.doWork(entity);
}
}
@Service
SomeOtherService {
@Autowired
EntityRepository entityRepository;
@Transactional
public doWork(Entity entity) {
// fetch lazy properties, save, etc. without any session problems...
entity.getLazyProperties();
entityRepository.save(entity);
}
}
这取决于映射如何发生以及在何处发生 如果要将@Async与惰性加载一起使用,则使用@Transactional声明的方法必须实现惰性加载的逻辑
如果在@Transactional外部初始化了惰性加载,则加载将不起作用。是否使用Spring管理的SessionFactory和TransactionManager?。你能展示这个方法的代码吗?这个方法是在加载实体还是只是在访问它?@eldermel,我已经更新了我的答案。在这种情况下,你可以实现一个允许跨线程和调用线程保留会话的方法。我在使用@async时也遇到了同样的问题。我尝试了很多事情,最后通过打开一个新的会议,做一些事情,然后结束会议来处理它。我不确定这是否是一个理想的解决方案,但考虑到hibernate会话和线程在一起时有一些个人问题,我对这个解决方案很满意。谢谢你的回答。我的方法已经是事务性的了!
@Controller
ControllerBean {
@Autowired
AsyncService asyncService;
public controllerMethod() {
asyncService.asyncMethod();
}
}
@Service
AsyncService {
@Autowired
TransactionalService transactionalService;
@Async
public asyncMethod() {
transactionalService.transactionalMethod();
}
}
@Service
TransactionalService {
@Autowired
SomeOtherService someOtherService;
@Autowired
EntityRepository entityRepository;
@Transactional
public transactionalMethod() {
Entity entity = entityRepository.findOne(12345);
someOtherService.doWork(entity);
}
}
@Service
SomeOtherService {
@Autowired
EntityRepository entityRepository;
@Transactional
public doWork(Entity entity) {
// fetch lazy properties, save, etc. without any session problems...
entity.getLazyProperties();
entityRepository.save(entity);
}
}