Spring数据:@Transactional和传播
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring数据:@Transactional和传播相关的知识,希望对你有一定的参考价值。
我有以下代码:
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
(懒惰的loded集合)和method2()
尝试加载所有链接的entities
。
现在,在method2
,我得到了
无法初始化代理 - 没有会话
错误,因为它在事务之外(预期的行为)。为了防止这种情况,有两种解决方案:
- 用
method1
注释@Transactional
。这将解决它,但是,在方法执行完成之前,state
将不会反映到其他事务。 - 更改实体配置中的
fetch mode
并使其成为Eager
。这也可以解决它,但我不希望eager
每次都取出。
有没有其他方法可以让它发挥作用?
这个怎么样:
选项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方法下运行,但是当状态要改为'running'时,那么:
- 当前交易将被暂停
- 将创建一个新的
- 国家将被改变和交易承诺
- 父事务将继续,您可以使用您的大型操作进行处理,而不会出现其他用户在2小时内看不到状态更改的问题。
选项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");
}
}
围绕一个执行了几个小时的方法进行交易似乎是一个设计错误,所以method1()
不应该有@Transactional!当您启动事务时,您需要一个连接,并且此连接将在整个持续时间内从您的连接池中分配,这极大地限制了可伸缩性(以及DBA的生命)。
无法初始化代理 - 没有会话
你得到这个错误是因为(在method1上没有@Transactional)你的实体在调用repository.save()
后被分离,你无法加载延迟集合。对此的快速解决方案是将EntityManager注入object2并在EntityManager.refresh()
中调用method2()
,这不需要事务,因为您只是在读取数据。
没有理由使用任何类型的事务传播来解决此问题。
以上是关于Spring数据:@Transactional和传播的主要内容,如果未能解决你的问题,请参考以下文章
Spring @Transactional 与跨多个数据源的事务
Spring——事务注解@Transactional建议收藏