在传统软件中混合程序化和声明性事务

时间:2016-02-11 14:07:03

标签: java spring hibernate

我的问题是关于混合程序化和声明式事务可能出现的并发问题。我正在开发一种遗留软件(Spring + Hibernate),它以编程方式处理数据库连接和事务。

Session db = HibernateUtil.getSessionFactory().openSession();
db.beginTransaction();
// do stuff
db.getTransaction().commit();

该软件具有更新的模块,这些模块使用Spring数据架构和声明式事务(@Transactional)。当从“手动”打开的事务内部调用较新的Spring服务时,我们在极少数情况下使用Microsoft SQL Server遇到数据库死锁。我认为问题是有两个嵌套事务读/写同一个表导致死锁。

Session db = HibernateUtil.getSessionFactory().openSession();
db.beginTransaction();
// do stuff
springService.getStuff();
// do stuff
db.getTransaction().commit();

有没有办法安全地混合这些交易或在两者中使用已经启动的交易?我应该在调用Spring @ Service / @ Repository方法之前关闭手动/以编程方式打开的事务吗? Spring和HibernateUtil都使用相同的实体管理器进行数据库连接。

1 个答案:

答案 0 :(得分:6)

当涉及到交易的行为时,声明性和程序性/手动性之间确实没有区别。声明性事务使您能够以更简洁和可读的方式划分事务边界,这就是它的全部内容。在引擎盖下,Spring将执行与手动启动和提交/回滚事务相同的操作。

  

我认为问题在于有两个嵌套事务   读/写相同的表导致死锁。

非常可能。

  

有没有办法安全地混合这些交易或使用已经完成的交易   两者都开始了交易?

在特定部件代码中执行此操作是否安全在很大程度上取决于代码的作用。如果嵌套事务会导致死锁,那么它显然是不安全的,并且与获取嵌套事务的方式无关(手动或Spring在拦截使用@Transactional(propagation = Propagation.PROPAGATION_REQUIRES_NEW)注释的方法时启动它。)

  

我应该只关闭手动/以编程方式打开的事务   在调用Spring @Service / @Repository方法之前?

再次,取决于你需要解决的问题。如果在嵌套事务完成后需要外部事务继续,那么您不应该。否则你可以。

TransactionTemplate是手动启动Spring事务的推荐方法,因为Spring知道事务边界,这意味着它会像使用Spring注释以声明方式启动一样处理这样的事务。