我有以下代码:
public void method1(String id){
Object object = repository.findOne(id);
object.setState("running");
repository.save(object);
try{
object2.method2(object); //This method takes 2 hours to complete
object.setState("complete");
}catch(Exception e){
object.setState("failed");
}
repository.save(object);
}
因此,在调用需要数小时执行的方法之前,我将状态更改为“running”。我的对象是JPA Entity
(包含懒惰的集合),method2()
尝试加载所有链接的entities
。
现在,在method2
,我正在
无法初始化代理 - 没有会话
错误,因为它超出了事务(预期的行为)。为了防止这种情况,有两种解决方案:
method1
注释@Transactional
。这将解决它,但是,在方法执行完成之前,state
将不会反映到其他事务。fetch mode
并将其设为Eager
。这也可以解决它,但我不希望每次eager
取出。还有其他方法可以让它发挥作用吗?
答案 0 :(得分:1)
这个怎么样:
选项1
1)为状态更改创建服务方法,如下所示:
@Transactional( propagation = Propagation.REQUIRES_NEW)
public void changeStatusInNewTransaction(String id, String status){
Object object = repository.findOne(id);
object.setState(status);
repository.save(object);
}
2)按如下方式更改原始方法:
@Autowired
Service service;
@Transactional
public void method1(String id){
service.changeStatusInNewTransaction(id, "running");
Object object = repository.findOne(id);
try{
object2.method2(object); //This method takes 2 hours to complete
object.setState("complete");
}catch(Exception e){
object.setState("failed");
}
repository.save(object);
}
由于这个设置,一切都可以在一个@Transactional方法下运行,但是当状态要改为'运行'然后:
选项2
1)为状态更改创建服务方法,如下所示:
@Transactional
public void changeStatusInNewTransaction(String id, String status){
Object object = repository.findOne(id);
object.setState(status);
repository.save(object);
}
2)仅为长时间处理创建交易方法
@Transactional
public void performLongProcessing(String id){
Object object = repository.findOne(id);
object2.method2(object); //This method takes 2 hours to complete
object.setState("complete");
repository.save(objects;
}
3)标记主要方法,无需交易即可运行:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method1(String id){
service.changeStatusInNewTransaction(id, "running");
try{
service.performLongProcessing(id);
}catch(Exception e){
service.changeStatusInNewTransaction(id, "failed");
}
}
答案 1 :(得分:1)
围绕一个执行了几个小时的方法的事务,似乎是一个设计错误,所以method1()
不应该有@Transactional!当您启动事务时,您需要一个连接,并且此连接将在整个持续时间内从您的连接池中分配,这极大地限制了可伸缩性(以及您的DBA的生命)。
无法初始化代理 - 没有会话
您收到此错误是因为(在method1上没有@Transactional)您的实体在调用repository.save()
后被分离,并且您无法加载延迟集合。一个快速解决方案是将EntityManager注入object2并在EntityManager.refresh()
内调用method2()
这不需要事务,因为您只是在读取数据。
没有理由使用任何类型的事务传播来解决此问题。