对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
了解 Spring Framework 事务抽象
Spring 事务抽象的关键是事务策略的概念。 一个 事务策略由TransactionManager
,具体来说org.springframework.transaction.PlatformTransactionManager
命令式事务管理和org.springframework.transaction.ReactiveTransactionManager
用于响应式事务管理的接口。以下列表显示了PlatformTransactionManager
应用程序接口:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
这主要是一个服务提供商接口 (SPI),尽管您可以从应用程序代码中以编程方式使用它。 因为PlatformTransactionManager
是一个接口,它很容易被模拟或存根为 必要。 它不与查找策略(如 JNDI)绑定。PlatformTransactionManager
实现的定义与任何其他对象(或 bean)一样在 Spring Framework IoC 容器中。仅此一项优势就使 Spring Framework事务成为一个有价值的抽象,即使您使用 JTA 也是如此。您可以测试事务代码比直接使用 JTA 要容易得多。
同样,为了与 Spring 的理念保持一致,该TransactionException
可以抛出的由任何PlatformTransactionManager
接口的方法未选中(即即,它扩展了java.lang.RuntimeException
类)。事务基础设施故障几乎总是致命的。在极少数情况下,应用程序代码实际上可以从事务故障中恢复,应用程序开发人员仍然可以选择捕获并处理TransactionException
. 突出的一点是,开发人员不是被迫这样做的。
这getTransaction(..)
方法返回一个TransactionStatus
对象,具体取决于TransactionDefinition
参数。 返回的TransactionStatus
可能表示new 事务,或者可以表示现有事务,如果匹配的事务存在于当前调用堆栈中。后一种情况下的含义是,与Jakarta EE 事务上下文一样,一个TransactionStatus
与 执行。
从 Spring Framework 5.2 开始,Spring 还为使用响应式类型或 Kotlin 协程的响应式应用程序提供了事务管理抽象。以下列表显示了由org.springframework.transaction.ReactiveTransactionManager
:
public interface ReactiveTransactionManager extends TransactionManager {
Mono<ReactiveTransaction> getReactiveTransaction(TransactionDefinition definition) throws TransactionException;
Mono<Void> commit(ReactiveTransaction status) throws TransactionException;
Mono<Void> rollback(ReactiveTransaction status) throws TransactionException;
}
响应式事务管理器主要是一个服务提供商接口 (SPI),尽管您可以从应用程序代码中以编程方式使用它。 因为ReactiveTransactionManager
是一个接口,它可以很容易地根据需要进行模拟或存根。
这TransactionDefinition
接口指定:
-
传播:通常,事务范围内的所有代码都在该事务中运行。但是,您可以在以下情况下指定行为当事务上下文已经存在时,将运行事务方法。 为 例如,代码可以继续在现有事务中运行(常见情况),或者可以暂停现有事务并创建新事务。 Spring 提供了 EJB CMT 熟悉的所有事务传播选项。要阅读关于 Spring 中事务传播的语义,请参阅事务传播。
-
隔离:此事务与其他事务的隔离程度 交易。 例如,此事务是否可以查看来自其他事务的未提交写入 交易?
-
超时:此事务在超时并自动回滚之前运行了多长时间由底层事务基础设施。
-
只读状态:当代码读取但不修改数据时,您可以使用只读事务。在某些情况下,只读事务可能是一种有用的优化情况,例如当您使用 Hibernate 时。
这些设置反映了标准事务概念。如有必要,请参阅资源其中讨论事务隔离级别和其他核心事务概念。了解这些概念对于使用 Spring Framework 或任何事务管理解决方案至关重要。
这TransactionStatus
接口为事务代码提供了一种简单的方法
控制事务执行并查询事务状态。概念应该是
熟悉,因为它们是所有事务 API 通用的。以下列表显示了TransactionStatus
接口:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
@Override
boolean isNewTransaction();
boolean hasSavepoint();
@Override
void setRollbackOnly();
@Override
boolean isRollbackOnly();
void flush();
@Override
boolean isCompleted();
}
无论您选择声明式还是编程式事务管理
弹簧,定义正确的TransactionManager
实施是绝对必要的。
通常通过依赖项注入来定义此实现。
TransactionManager
实现通常需要了解环境中的环境
它们工作:JDBC、JTA、Hibernate 等。以下示例演示了如何
定义本地PlatformTransactionManager
实现(在本例中,使用 plain
JDBC。
您可以定义 JDBCDataSource
通过创建一个类似于以下内容的 bean:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
相关PlatformTransactionManager
bean 定义则引用了DataSource
定义。它应该类似于以下示例:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
如果您在 Jakarta EE 容器中使用 JTA,则使用DataSource
获得
通过 JNDI 与 Spring 的JtaTransactionManager
.以下示例
显示了 JTA 和 JNDI 查找版本的外观:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
https://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- other <bean/> definitions here -->
</beans>
这JtaTransactionManager
不需要知道DataSource
(或任何其他
特定资源),因为它使用容器的全局事务管理
基础设施。
前面的定义dataSource bean 使用<jndi-lookup/> 标记
从jee Namespace。有关详细信息,请参阅 JEE 架构。 |
如果您使用 JTA,则无论如何,您的事务管理器定义都应该看起来相同 您使用的数据访问技术,无论是 JDBC、Hibernate JPA 还是任何其他受支持的技术 科技。这是因为 JTA 事务是全局事务,而 可以征用任何事务资源。 |
在所有 Spring 事务设置中,应用程序代码不需要更改。您可以更改 如何仅通过更改配置来管理事务,即使该更改意味着 从本地交易转移到全球交易,反之亦然。
Hibernate 事务设置
您还可以轻松使用 Hibernate 本地事务,如以下示例所示。
在这种情况下,您需要定义一个 HibernateLocalSessionFactoryBean
,您的
应用程序代码可用于获取 HibernateSession
实例。
这DataSource
bean 定义类似于前面显示的本地 JDBC 示例
因此,以下示例中未显示。
如果DataSource (由任何非 JTA 事务管理器使用)通过以下方式进行查找
JNDI 并由 Jakarta EE 容器管理,它应该是非事务性的,因为
Spring Framework(而不是 Jakarta EE 容器)管理事务。 |
这txManager
在这种情况下,bean 是HibernateTransactionManager
类型。在
与DataSourceTransactionManager
需要引用DataSource
这HibernateTransactionManager
需要引用SessionFactory
.以下内容
示例声明sessionFactory
和txManager
豆:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
如果您使用 Hibernate 和 Jakarta EE 容器管理的 JTA 事务,则应使用
相同JtaTransactionManager
如前面的 JDBC JTA 示例,如下所示
示例显示。此外,建议通过其
事务协调器,可能还有它的连接释放模式配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
hibernate.transaction.coordinator_class=jta
hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
或者,您可以将JtaTransactionManager
进入您的LocalSessionFactoryBean
用于强制执行相同的默认值:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
<property name="jtaTransactionManager" ref="txManager"/>
</bean>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>