【问题标题】:Mixing programmatic and declarative transactions in legacy software在遗留软件中混合编程和声明性事务
【发布时间】:2016-02-11 14:07:02
【问题描述】:

我的问题涉及混合编程和声明式事务可能出现的并发问题。我正在开发一个以编程方式处理数据库连接和事务的遗留软件(Spring + Hibernate)。

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

该软件具有使用带有声明性事务 (@Transactional) 的 Spring 数据架构的更新模块。当从“手动”打开的事务内部调用较新的 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 都使用相同的实体管理器进行数据库连接。

【问题讨论】:

    标签: java spring hibernate


    【解决方案1】:

    当涉及到事务的行为时,声明式和程序化/手动的确实没有区别。声明式事务使您能够以更简洁和可读的方式划分事务边界,仅此而已。在后台,Spring 将执行与手动启动和提交/回滚事务相同的操作。

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

    很有可能。

    有没有办法安全地混合这些交易或使用已经 双方都开始交易了吗?

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

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

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

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

    【讨论】:

    • 你知道是否可以将手动启动的事务传播到 Spring @Transactional 方法?
    • @anssias 你可以看看TransactionTemplate。如果您以这种方式开始事务,它将起作用,因为 Spring 会知道该事务。
    • 这看起来更像我想要的。您能否将其添加到您的答案中,我会接受它作为答案。谢谢!
    猜你喜欢
    • 2011-09-14
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 2013-02-03
    • 2011-02-23
    • 2018-08-15
    • 2016-09-17
    • 1970-01-01
    相关资源
    最近更新 更多