






















Spring源码学习系列博客专栏:链接
Spring5.0源码学习系列之事务管理概述(十一),在学习事务管理的源码之前,需要对事务的基本理论比较熟悉,所以本章节会对事务管理的基本理论进行描述
事务就是一组原子性的SQL操作,或者说一个独立的工作单元。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)
注意:Spring的事务支持是基于数据库事务的,在MySQL数据库中目前只有InnoDB或者NDB集群引擎才支持,MySQL5.0之前的默认MyISAM存储引擎是不支持事务的
ACID其实是事务特性的英文首字母缩写,具体含义是:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)




定义:事务的隔离级别定义了一个事务可能受其他并发事务影响的程度。隔离级别可以不同程度的解决脏读、不可重复读、幻读。
| 隔离级别 | 描述 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|---|
| 事务传播行为 | 描述 |
|---|---|
前面介绍了事务管理的隔离级别和传播行为这两个重要的属性,接着介绍一下事务的其它属性
| 属性名 | 说明 |
|---|---|
Spring事务代码实现方式有两种,一种是编程式事务,一种是声明式事务。所谓编程式事务,是指通过Spring框架提供的TransactionTemplate或者直接使用底层的PlatformTransactionManager。声明式事务,依赖Spring AOP,配置文件中做相关的事务规则声明或者直接使用@Transactional注解
下面给出一个典型的转账汇款例子,先不用事务的方式实现,接着使用编程式事务和声明式事务进行事务管理
package com.example.springframework.dao.impl;
import com.example.springframework.dao.AccountDao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
/**
* <pre>
* AccountDaoImpl
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2021/03/25 15:51 修改内容:
* </pre>
*/
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void out(String outer, int money) {
super.getJdbcTemplate().update("update account set money = money - ? where usercode=?",money,outer);
}
@Override
public void in(String inner, int money) {
super.getJdbcTemplate().update("update account set money = money + ? where usercode = ?",money , inner);
}
}
package com.example.springframework.service.impl;
import com.example.springframework.dao.AccountDao;
import com.example.springframework.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Service;
/**
* <pre>
* AccountServiceImpl
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2021/03/25 15:55 修改内容:
* </pre>
*/
@Service
public class AccountServiceImpl extends JdbcDaoSupport implements AccountService {
AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(final String outer,final String inner,final int money){
accountDao.out(outer , money);
// exception
// int i = 1 / 0;
accountDao.in(inner , money);
}
}
代码例子看起来是挺正常的,不过假如在accountDao.out(outer , money);, accountDao.in(inner , money);两个事务执行期间,发生异常,这时会怎么样?效果如图:Jack的账号已经转账成功,转了1000,不过Tom并没有收到汇款,这种情况在实际生活中肯定是不允许的,所以需要使用事务进行管理

Spring编程式事务实现,通过Spring框架提供的TransactionTemplate或者直接使用底层的PlatformTransactionManager
TransactionTemplate的方式private AccountDao accountDao;
private TransactionTemplate transactionTemplate;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void transfer(final String outer,final String inner,final int money){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.out(outer , money);
// exception
int i = 1 / 0;
accountDao.in(inner , money);
}
});
}
PlatformTransactionManager的方式private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transferTrans(String outer, String inner, int money) {
DataSourceTransactionManager dataSourceTransactionManager =
new DataSourceTransactionManager();
// 设置数据源
dataSourceTransactionManager.setDataSource(super.getJdbcTemplate().getDataSource());
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
// 设置传播行为属性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef);
try {
accountDao.out(outer , money);
// exception
int i = 1 / 0;
accountDao.in(inner , money);
//commit
dataSourceTransactionManager.commit(status);
} catch (Exception e) {
// rollback
dataSourceTransactionManager.rollback(status);
}
}
Spring声明式事务依赖于Spring AOP,通过配置文件中做相关的事务规则声明或者直接使用@Transactional注解
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="minstone"></property>
</bean>
<bean id="accountDao" class="com.example.springframework.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="accountService" class="com.example.springframework.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- xml配置事务 propagation 传播行为isolation 隔离级别-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 配置所有的Service方法都支持事务-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.example.springframework.service..*.*(..))"/>
</aop:config>
</beans>
注意点:@Transactional只能用于public方法,不管是加上类上还是方法上
<!-- 事务管理器配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
通过上述管理之后,一旦发生异常,两边都会进行事务回滚,没有异常,正常提交事务

本文例子代码可以在github找到下载链接
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。