多线程Spring事务

15

假设我们进入一个方法并在主线程中启动一个事务。在这个方法中,有一些异步方法,因此我们在该方法内创建了另外2个线程。

                 Thread 1 --> SubMethod1 --> Saving (t=1)
                   ^
                   |
MainThread --> MainMethod --> Saving (t=3)
                   |
                   v   
                 Thread 2 --> SubMethod2 --> Exception while saving (t=2).

由于线程2出现异常,我希望回滚其他线程执行的所有事务。然而,虽然主线程和线程2拥有的事务可以被回滚,但我无法回滚线程1的工作。

我正在使用Spring/Hibernate,你有什么管理这个问题以及如何应用的想法吗?

谢谢。


2
不要使用线程。事务是线程绑定的,而且你有多个事务。你不能回滚已提交的事务。唯一的“解决方案”就是手动撤销工作(删除记录、恢复旧状态等)。 - M. Deinum
已在此回答:https://dev59.com/xorda4cB1Zd3GeqPNozX#30091149 - Aníbal
2个回答

13
从《专业Java Web应用程序》(作者:Nicholas S. Williams)中:
Spring中的事务范围仅限于事务开始的线程。然后,事务管理器将在事务的生命周期内将事务链接到同一线程中使用的受管资源。当使用Java持久化API时,您使用的资源是EntityManager。它在功能上相当于Hibernate ORM的Session和JDBC的Connection。通常,在开始事务并执行JPA操作之前,您会从EntityManagerFactory获取一个EntityManager。然而,这在Spring框架模型中无法正常工作,因为它会代表您管理事务。解决此问题的方法是使用org.springframework.orm.jpa.support.SharedEntityManagerBean。当您在Spring框架中配置JPA时,它会创建一个代理EntityManager接口的SharedEntityManagerBean。然后将此代理注入到您的JPA存储库中。当在此代理实例上调用EntityManager方法时,背后会发生以下情况:
➤➤ 如果当前线程已经具有具有活动事务的真实EntityManager,则将调用委托给该EntityManager上的方法。
➤➤ 否则,Spring Framework 从 EntityManagerFactory 获取一个新的 EntityManager,启动一个事务,并将它们绑定到当前线程。然后,它将调用该 EntityManager 上的方法。当事务提交或回滚时,Spring 解除事务和 EntityManager 与线程的绑定,然后关闭 EntityManager。在同一线程上的未来 @Transactional 操作(即使在同一请求中)会重新开始这个过程,从工厂获取一个新的 EntityManager 并开始一个新的事务。这样,没有两个线程同时使用一个 EntityManager,并且给定线程在任何给定时间只有一个事务和一个活动的 EntityManager。
如果你不使用Spring MVC,那么你可以通过Hibernate中的SessionFactory来获取会话。Hibernate会话代表了一个事务从开始到结束的生命周期。根据应用程序的架构,这个过程可能持续不到一秒钟或几分钟;在Web应用程序中,它可能是请求中的几个事务之一,一个完整请求的事务,或者涉及多个请求的事务。Session不是线程安全的,每次只能在一个线程中使用,它负责管理实体的状态。

假设一个端点需要从3个表中DELETE FROM,然后再将这些相同的3个表中进行INSERT INTO。插入需要从另外2个不相关的表中进行SELECT。没有办法通过一起发出所有的DELETE(每个表请求在单独的线程中执行)以及SELECT(同样:每个DB请求一个线程)来多线程化此端点,然后跟随着一个阻塞调用等待所有结果,最终在它们自己的线程中发出INSERT吗?(所有这些共计5个线程处理所有8个请求,而不是一个线程按顺序完成整个工作。) - payne
@payne,目前我无法回答这个问题。 - Faraz

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接