1. spring 事务管理抽象
spring 的事务策略机制的核心就是 org.springframework.transaction.PlatformTransactionManager
接口。
public interface PlatformTransactionManager { TransactionStatus getTransaction(
TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException;
}
在 PlatformTransactionManager
的方法运行出错时,都会抛出 TransactionException 异常,而这个异常几乎都是致命的,不可修复的。
getTransaction(..)
方法会根据对 TransactionDefinition 对象的处理结果返回一个 TransactionStatus 对象。 TransactionStatus 对象则表示一个事务的状态,表示该事务是否是一个新的事务,是否 commit 或 rollback 等。
public interface TransactionStatus extends SavepointManager { /**
* 是新的事务还是已存在的事务
*/
boolean isNewTransaction(); /**
* 是否有 savePoint*/
boolean hasSavepoint(); /**
* Set the transaction rollback-only. */
void setRollbackOnly(); /**
* 该事务是否已标记 rollback-only
*/
boolean isRollbackOnly(); /**
* Flush the underlying session to the datastore, if applicable:
* for example, all affected Hibernate/JPA sessions.
*/
void flush(); /**
* Return whether this transaction is completed, that is,
* whether it has already been committed or rolled back.*/
boolean isCompleted(); }
而 TransactionDefinition
接口则定义了下面几个属性
- Isolation 隔离性级别
- Propagation 传播属性:在事务上下文存在或者不存在时,可以指定方法的 tansaction 行为(新创建,使用已有的还是抛出异常)
-
Timeout: 超时时间
- 时间单位 s
- 表示在该时间内如果函数还没有执行完成,就会 rollback
- Read-only status: 当代码中只是读取数据,而不修改数据时,可以使用该属性。
在和 mybatis 配合时,一般会使用 DataSourceTransactionManager, 它们的继承关系如下:
下面就以 spring-mybatis 给出配置事务的实例
1. 定义 DataSource
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="${jdbc.initialSize}"></property>
<property name="maxActive" value="${jdbc.maxActive}"></property>
<property name="maxIdle" value="${jdbc.maxIdle}"></property>
<property name="minIdle" value="${jdbc.minIdle}"></property>
<property name="maxWait" value="${jdbc.maxWait}"></property>
</bean>
2. 定义 DataSourceTransactionManager bean, 此时需要引用前面配置的 DataSource Bean
<!-- 声明事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3. 如果是使用基于注解的 spring 声明式事务管理, 需要如下配置
<tx:annotation-driven transaction-manager="transactionManager"/>
2. 声明式事务管理
2.1 对声明式事务管理机制的理解
spring 声明式事务管理是使用 AOP 代理实现的, transaction advice 事务通知是由元数据(注解或者 XML)驱动的。(待完善。。。)
2.2 @Transactional 注解
在上节最后我们已经说明,要使用基于注解的 spring 声明式事务,需要在 xml 中使用 <tx:annotation 配置。
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:annotation-driven 配置
XML 属性 | 默认值 | 描述 |
transaction-manager |
transactionManager |
如果声明的transaction manager 名字不是
transactionManager才需要配置 |
mode | proxy | 有 proxy, aspectj 两种模式可选 |
proxy-target-class |
false |
只对 proxy 模式有效。是基于接口的还是基于类的代理被创建。 true,那么基于类的代理将起作用(这时需要cglib库) false,使用标准的JDK 基于接口的代理理 |
order | Ordered.LOWEST_PRECEDENCE |
Defines the order of the transaction advice that is applied to beans annotated with |
@Transactional 配置
@Transactional 既可以注解在 class 上,也可以注解在 method 上。
有下面几点需要注意
- 尽量注解在具体实现类中(大部分情况是 service 实现类),注解在接口上也可以,但还需要其他的配置才能生效,此处不会讲述。
- 在注解到 method 上时,该 method 需要是 public 修饰符修饰,在 proxy 默认模式下,注解在 package或者 private 方法上不会报错,但也不会生效。
参考链接: https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html#tx-multiple-tx-mgrs-with-attransactional