多线程 Spring 事务
Multi-threading Spring Transaction
假设我们进入一个方法并在主线程中启动一个事务。在这个方法中,有一些异步方法,所以我们在这个方法中创建了 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,所以你有什么想法来管理这个以及如何申请吗?
谢谢
来自Professional Java for Web Applications by Nicholas S. Williams
Spring 中的事务范围仅限于事务开始的线程。事务管理器然后将事务链接到事务生命周期中同一线程中使用的托管资源。使用 Java 持久性 API 时,您使用的资源是 EntityManager
。它在功能上等同于 Hibernate ORM 的 Session 和 JDBC 的 Connection。通常,您会在开始事务和执行 JPA 操作之前从 EntityManagerFactory
获取 EntityManager
。但是,这不适用于代表您管理事务的 Spring 框架模型。这个问题的解决方案是org.springframework.orm.jpa.support.SharedEntityManagerBean
。当您在 Spring 框架中配置 JPA 时,它会创建一个 SharedEntityManagerBean
来代理 EntityManager
接口。然后将此代理注入到您的 JPA 存储库中。在此代理实例上调用 EntityManager
方法时,后台会发生以下情况:
➤➤ 如果当前线程已经有一个具有活动事务的真实 EntityManager
,它会将调用委托给该 EntityManager
上的方法。
➤➤ 否则,Spring 框架从 EntityManagerFactory
获得一个新的 EntityManager
,启动一个事务,并将两者绑定到当前线程。然后它将调用委托给 EntityManager
上的方法。当事务提交或回滚时,Spring 从线程中解除事务和 EntityManager
的绑定,然后关闭 EntityManager
。同一线程上的未来 @Transactional
操作(即使在同一请求中)会重新开始该过程,从工厂获取新的 EntityManager
并开始新的事务。这样,不会有两个线程同时使用 EntityManager
,并且给定线程在任何给定时间只有一个事务和一个 EntityManager
处于活动状态。
如果您不使用Spring MVC,那么您将使用SessionFactory
获取会话在休眠中。 Hibernate Sessions 代表事务从开始到结束的生命周期。根据您的应用程序的架构方式,这可能不到一秒或几分钟;在 Web 应用程序中,它可以是请求中的多个事务之一、持续整个请求的事务或跨越多个请求的事务。 Session
,它不是线程安全的,一次只能在一个线程中使用,负责管理实体的状态。
这个 post https://dzone.com/articles/spring-transaction-management-over-multiple-thread-1 似乎很好地涵盖了这个问题,并提到了一个正在做类似事情的项目。
假设我们进入一个方法并在主线程中启动一个事务。在这个方法中,有一些异步方法,所以我们在这个方法中创建了 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,所以你有什么想法来管理这个以及如何申请吗?
谢谢
来自Professional Java for Web Applications by Nicholas S. Williams
Spring 中的事务范围仅限于事务开始的线程。事务管理器然后将事务链接到事务生命周期中同一线程中使用的托管资源。使用 Java 持久性 API 时,您使用的资源是 EntityManager
。它在功能上等同于 Hibernate ORM 的 Session 和 JDBC 的 Connection。通常,您会在开始事务和执行 JPA 操作之前从 EntityManagerFactory
获取 EntityManager
。但是,这不适用于代表您管理事务的 Spring 框架模型。这个问题的解决方案是org.springframework.orm.jpa.support.SharedEntityManagerBean
。当您在 Spring 框架中配置 JPA 时,它会创建一个 SharedEntityManagerBean
来代理 EntityManager
接口。然后将此代理注入到您的 JPA 存储库中。在此代理实例上调用 EntityManager
方法时,后台会发生以下情况:
➤➤ 如果当前线程已经有一个具有活动事务的真实 EntityManager
,它会将调用委托给该 EntityManager
上的方法。
➤➤ 否则,Spring 框架从 EntityManagerFactory
获得一个新的 EntityManager
,启动一个事务,并将两者绑定到当前线程。然后它将调用委托给 EntityManager
上的方法。当事务提交或回滚时,Spring 从线程中解除事务和 EntityManager
的绑定,然后关闭 EntityManager
。同一线程上的未来 @Transactional
操作(即使在同一请求中)会重新开始该过程,从工厂获取新的 EntityManager
并开始新的事务。这样,不会有两个线程同时使用 EntityManager
,并且给定线程在任何给定时间只有一个事务和一个 EntityManager
处于活动状态。
如果您不使用Spring MVC,那么您将使用SessionFactory
获取会话在休眠中。 Hibernate Sessions 代表事务从开始到结束的生命周期。根据您的应用程序的架构方式,这可能不到一秒或几分钟;在 Web 应用程序中,它可以是请求中的多个事务之一、持续整个请求的事务或跨越多个请求的事务。 Session
,它不是线程安全的,一次只能在一个线程中使用,负责管理实体的状态。
这个 post https://dzone.com/articles/spring-transaction-management-over-multiple-thread-1 似乎很好地涵盖了这个问题,并提到了一个正在做类似事情的项目。