🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
Spring事务抽象的关键是事务策略的概念。事务策略定义在`org.springframework.transaction.PlatformTransactionManager`接口里: ~~~java public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; } ~~~ 这主要是服务提供者接口(SPI),尽管它可以从您的应用程序代码中以编程方式使用。 因为`PlatformTransactionManager`是一个接口,所以可以根据需要轻松地模拟或存根。 它与诸如JNDI之类的查找策略无关。 `PlatformTransactionManager`实现的定义与Spring Framework IoC容器中的任何其他对象(或bean)相同。 仅此优势,即使您使用JTA,Spring Framework事务也是值得抽象的。 与直接使用JTA相比,可以更轻松地测试事务代码。 与Spring的理念保持一致,任何PlatformTransactionManager接口的方法抛出的TransactionException都是未经检查的(也就是说,它扩展了java.lang.RuntimeException类)。 交易基础设施故障几乎总是致命的。 在极少数情况下,应用程序代码实际上可以从事务失败中恢复,应用程序开发人员仍然可以选择捕获并处理TransactionException。 重点是开发人员不会被迫这样做。 `getTransaction(..)`方法返回`TransactionStatus`对象,依赖于`TransactionDefinition`参数。 返回的`TransactionStatus`可能表示新事务,或者如果当前调用堆栈中存在匹配的事务,则可以表示现有事务。 后一种情况的含义是,与Java EE事务上下文一样,`TransactionStatus`与执行线程相关联。 ` TransactionDefinition` 接口的特点: * 传播: 一般一个事务内的代码都运行在同一个事务内,当然也可以暂停当前事务,新建事务,参考[事务传播](https://docs.spring.io/spring/docs/5.0.7.RELEASE/spring-framework-reference/data-access.html#tx-propagation) * 隔离:此事务与其他事务的工作隔离的程度。 例如,此事务是否可以看到来自其他事务的未提交的写入? * 超时:此事务在多久之后由底层事务自动回滚。 * 只读状态:当您的代码读取但不修改数据时,可以使用只读事务。 在某些情况下,只读事务可能是一种有用的优化,例如在使用Hibernate时。 这些设置反映了标准的事务概念。 如有必要,请参阅讨论事务隔离级别和其他核心事务概念的资源。 理解这些概念对于使用Spring Framework或任何事务管理解决方案至关重要。 `TransactionStatus`接口为事务代码提供了一种控制事务执行和查询事务状态的简单方法。 应该熟悉这些概念,因为它们对于所有事务API都是通用的: ~~~java public interface TransactionStatus extends SavepointManager { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); void flush(); boolean isCompleted(); } ~~~ 无论在spring中使用声明式或编程式的事务管理,正确定义`PlatformTransactionManager `的实现都是非常重要的.一般是通过依赖注入定义实现. `PlatformTransactionManager `的实现一般需要了解工作的环境:JDBC, JTA, Hibernate等等. 定义jdbc数据源 ~~~xml <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 `引用`DataSource ` ~~~xml <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> ~~~ 如果你使用JTA在java企业级容器中,那么需要使用`JtaTransactionManager`通过JNDI获取`DataSource`: ~~~xml <?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://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`,它使用容器的全局事务管理. 也可以简单的使用Hibernate 的局部事务管理,需要定义Hibernate 的`LocalSessionFactoryBean`,用于获取Hibernate 会话实例 `DataSource `的配置同jdbc,这里就不再赘述.`HibernateTransactionManager `需要引用`SessionFactory` ~~~xml <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 并且也使用了全局事务JTA,如下配置 ~~~xml <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> ~~~