Spring的事物管理的高层级抽象有三个:
- PlatformTransactionManager
- TransactionDefinition
- TransactionStstus
这三个接口之间的关系:PlantformTransactionManager根据TransactionDefinition进行事物管理,管理过程中会出现许多的事物状态,每个状态信息通过TransactionStstus展示。
1)不同平台的不同实现
PlatformTransactionManager的实现类
org.springframework.jdbc.DataSourceTransactionManager
Org.springframework.orm.hibernate3HibernateTransactionManager
org.springframework.jdc.JdoTrasactionManager
org.springframework.transaction.jta.JtaTransactionManager
针对不同的事务,我们要选用不同的实现。
- 事物的隔离级别
- Read uncommitted读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。
- Read committed读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
- Repeatable read重复读,就是在开始读取数据(事务开启)时,不再允许修改操作
- Serializable 序列化Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
package org.springframework.transaction.annotation;
public enum Isolation {
DEFAULT(-1),
READ_UNCOMMITTED(1),
READ_COMMITTED(2),
REPEATABLE_READ(4),
SERIALIZABLE(8);
private final int value;
private Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
3)事务的传播行为(一个业务的执行调用了另一个业务层事务,事务之间的关系如何处理)
SPring定义了7种事物的传播行为
/* 处于同一个事务中 */
int PROPAGATION_REQUIRED = 0; // 支持当前事物,如果不存在就新建一个。删除客户和删除订单处于同一个事务,如果删除订单失败,则删除客户也要失败
int PROPAGATION_SUPPORTS = 1; // 支持当前事物,如果不存在,就不使用事务
int PROPAGATION_MANDATORY = 2; // 支持当前事物,如果不存在,则抛出异常
/* 处于不同的事务,一个事物失败不影响另一个事物 */
int PROPAGATION_REQUIRES_NEW = 3; // 如果当前事务存在,则挂起当前事务,创建一个新的事务。生成订单,发送邮件通知客户,发邮件操作会创建一个新的事务,如果发送邮件失败,不影响订单的创建。
int PROPAGATION_NOT_SUPPORTED = 4; // 以非事务方式运行,如果当前事务存在,挂起当前事务
int PROPAGATION_NEVER = 5; // 以非事务的方式运行,如果当前事务存在,则直接抛出异常
/* 一个事物,不完全成功可恢复到Savepoint,可选择后续操作 */
int PROPAGATION_NESTED = 6; // 如果当前事务存在,则嵌套事务执行。依赖于JDK3.0 提供的SavePoint技术。删除客户,删除订单,在删除客户后,设置Savepoint,执行删除订单,删除订单和删除客户处在同一个事物中,如果删除订单失败,事务回滚Savepoint,由用户来控制事务提交还是回滚。
4)Spring的事物管理方式
- 编程式的事物管理。在代码中,通过TransactionTempalte来手动管理事务
- 声明式事务管理,在配置文件中,对我们定义的方法进行事务管理,基于AOP实现的。
编排式事物管理
<bean id="accountDao" class="com.andy.transaction.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.andy.transaction.AccountServiceImpl">
<property name="account" ref="accountDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
<!-- 配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="Andy"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="dataSourceTransactionManager"/>
</bean>
<!-- 事物管理器 用来管理jdbc操作的事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="datasource"/>
</bean>
将事务管理器注入事务模板,再将事务模板注入业务实现类,在业务实现类中使用事务管理模板的execute方法来执行操作。
/**
* 业务实现层
*/
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDaoImpl account;
private TransactionTemplate transactionTemplate;
@Override
public void transfer(final String out,final String in,final double num) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
account.outTransfer(out, num);
// int a= 1/0;
account.inTransfer(in, num);
}
});
}
public void setAccount(AccountDaoImpl account) {
this.account = account;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
}
4)声明式事务管理。无需更改类的结构,仅需要在xml配置文件中,声明事务管理,并配置即可。使用了org.springframework.transaction.interceptor.TransactionProxyFactoryBean
<bean id="accountDao" class="com.andy.claimTransaction.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.andy.claimTransaction.AccountServiceImpl">
<property name="account" ref="accountDao"/>
</bean>
<!-- 配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="Andy"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<bean id="transactionProxyFactoryBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 事务管理器-->
<property name="transactionManager" ref="dataSourceTransactionManager"/>
<!-- 目标-->
<property name="target" ref="accountService"/>
<!-- 针对接口代理 -->
<property name="proxyInterfaces" value="com.andy.claimTransaction.AccountService"/>
<!--
事务管理属性
针对目标方法设置具体需要事务管理的方法名,隔离级别,传播行为,是否只读等信息
-->
<property name="transactionAttributes">
<props>
<!-- 设置需要代理的方法-->
<!-- PROPAGATION 事务的传播行为 -->
<!-- ISOLUATION 事务隔离级别 -->
<!-- readOnly 事务只读,不能有更新操作 -->
<!-- -exception 事务出现异常就回滚 -->
<!-- +exception 事务出现异常也执行 -->
<prop key="transfer"></prop>
</props>
</property>
</bean>
缺点是需要为每个类创建事务代理bean,开发量巨大
5)基于tx配置,为目标类创建事务代理
- 导入aop和tx命名空间
- 定义事务管理器
- 利用tx标签创建通知
- 使用AOP自动代理配置tx:Advice的代理
<bean id="accountDao" class="com.andy.claimTransaction.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.andy.claimTransaction.AccountServiceImpl">
<property name="account" ref="accountDao"/>
</bean>
<!-- 配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="Andy"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 使用tx定义事务管理-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
<!-- 使用AOP进行自动代理 -->
<aop:config>
<!-- 定义切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.andy.claimTransaction.AccountServiceImpl.transfer(..))"/>
<!-- 定义切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:appClaimTransaction.xml")
public class ClaimTransactionTest {
@Autowired
@Qualifier("accountService")
private AccountService accountService;
@Test
public void test(){
accountService.transfer("aaa","bbb",1);
}
}
基于注解的事物管理
- 在需要管理的类或者方法上添加注解@Transactional
- 注解驱动注解管理
<bean id="accountDao" class="com.andy.AnnotationTransaction.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.andy.AnnotationTransaction.AccountServiceImpl">
<property name="account" ref="accountDao"/>
</bean>
<!-- 配置连接池 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///transactiondb?serverTimezone=Asia/Shanghai"/>
<property name="user" value="root"/>
<property name="password" value="Andy"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 注解事务管理 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
@Override
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED ,readOnly = false ,noRollbackFor = ArithmeticException.class)
public void transfer(final String out,final String in,final double num) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
account.outTransfer(out, num);
int a= 1/0;
account.inTransfer(in, num);
}
});
}
小结:
TransactionTemplate 编程式事务管理 了解
TransactionProxyFactoryBean 声明式事务管理 了解
基于tx和aop的xml配置 事务管理 重点掌握
基于tx以及@Transactional的事物管理 必须掌握