【发布时间】:2013-04-17 14:33:03
【问题描述】:
我将我正在开发的应用程序从使用 AspectJ 加载时间编织切换到使用 Spring CGlib 代理,在我这样做之后,我开始在代码的许多部分中出现休眠延迟加载异常,而在过去有没有抛出异常。
我已经能够通过将@Transactional(propagation = Propagation.SUPPORTS, readOnly = true) 添加到之前没有任何事务属性但调用 spring 存储库从数据库中读取数据的一组以前的公共方法来解决这些延迟加载异常。
任何人都知道为什么添加@Transactional(propagation = Propagation.SUPPORTS, readOnly = true) 会消除休眠延迟加载异常,以及为什么 AspectJ 加载时间编织不需要这些注释但在 out 时却需要这些注释?
更新 2 我认为删除 AspectJ 不是问题,但问题是我并不真正了解 SUPPORTS 传播的实际行为。特别是 SUPPORTS 如何与 JPA EntityManager 交互,因此我删除了一堆导致延迟加载异常的 SUPPORTS 传播。在阅读了 Spring Transaction Manager 的源代码之后,该做什么就变得很清楚了。 Spring 文档并没有很好地指出的关键思想是 @Transactional 注释用作将 EntityManager 的生命周期与事务方法的开始和结束联系起来的同步点。也强烈推荐这个系列文章http://www.ibm.com/developerworks/java/library/j-ts1/和这篇博文http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/
更新 1
这不是通过 AOP 代理调用私有 @Transactional 方法的情况。这些问题发生在从其他服务调用的公共方法中。
这是代码结构的示例,我在其中看到了问题的发生。
@Service
public class FooService
{
@Autowired
private BarService barService;
public void someMethodThatOnlyReads() {
SomeResult result = this.barService.anotherMethodThatOnlyReads()
// the following line blows up with a HibernateLazyLoadingEcxeption
// unless there is a @Transactional supports annotation on this method
result.getEntity().followSomeRelationship();
}
}
@Service
public class BarService
{
@Autowired
private BarRepository barRepo;
public SomeResult anotherMethodThatOnlyReads()
{
SomeEntity entity = this.barRepo.findSomeEntity(1123);
SomeResult result = new SomeResult();
result.setEntity(entity);
return result;
}
}
@Repository
public class BarRepository
{
@PersistenceContext
private EntityManager em;
public SomeEntity findSomeEntity(id Integer)
{
em.find(SomeEntity.class,id);
}
}
【问题讨论】: