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

ans*_*ias 9 java spring hibernate

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

Session db = HibernateUtil.getSessionFactory().openSession();
db.beginTransaction();
// do stuff
db.getTransaction().commit();
Run Code Online (Sandbox Code Playgroud)

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

Session db = HibernateUtil.getSessionFactory().openSession();
db.beginTransaction();
// do stuff
springService.getStuff();
// do stuff
db.getTransaction().commit();
Run Code Online (Sandbox Code Playgroud)

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

Dra*_*vic 8

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

我认为问题是有两个嵌套事务读/写同一个表导致死锁.

非常可能.

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

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

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

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

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