目标:事务失效引发的灾难
如下图(张三--->李四转账)
tips
下订单-------订单支付-----减库存(失败)
超卖现象
代码回忆:
//实现类
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Resource
private LogService logService;
@Override
@Transactional
// @Transactional(rollbackFor = Exception.class)
public void insert() throws Exception {
method1_Test();
}
//模拟转账@Transactional
private void method1_Test() throws Exception {
System.out.println(">>>>>>>>>>>进入到业务方法");
User user = new User();
user.setName("张三");
userMapper.insertUser(user);//张三扣减500元
addPayment();//模拟李四增加500元(检查异常)
}
//FileNotFoundException extends IOException
private void addPayment() throws FileNotFoundException {
FileInputStream in = new FileInputStream("a.txt");//模拟检查异常
}
}
......略
如果说你从从事务方法中抛出的是检查异常(io、sql),那么这个时候,Spring将不能进行事务回滚。
是不是很恐怖呢??
所以说,阿里规定
1、让检查异常也回滚:你就需要在整个方法前加上@Transactional(rollbackFor=Exception.class)
2、让非检查异常不回滚:
需要加入@Transactional(notRollbackFor=RunTimeException.class)
3、不需要事务管理(or 日志丢失)
需要加入@Transactional(propagation=Propagation.NOT_SUPPORTED)
课程目标总结
1、解决事务失效:通过源码学习如何让检查异常也回滚(or 运行异常不回滚);从源码角度深入底层原理
2、解决无需事务控制;查询 or 日志记录;通过传播属性如何控制;底层是如何实现的
3、正常的事务执行流程在源码中是如何实现的
1.1 Spring事务总体介绍
在Spring中,事务有两种实现方式:
-
编程式事务管理: 编程式事务管理使用TransactionTemplate可实现更细粒度的事务控制。
-
申明式事务管理: 基于Spring AOP实现。
其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务好处:
申明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单,且大部分业务都可以满足,推荐使用。
管是编程式事务还是申明式事务,最终调用的底层核心代码是一致的
1.1.1 编程式事务实现方式
编程式事务,Spring已经给我们提供好了模板类TransactionTemplate,可以很方便的使用,如下图
TransactionTemplate全路径名是:org.springframework.transaction.support.TransactionTemplate。这是spring对事务的模板类
实现的接口
用来执行事务的回调方法,
public interface TransactionOperations {
@Nullable
<T> T execute(TransactionCallback<T> action) throws TransactionException;
}
InitializingBean这个是典型的spring bean初始化流程中 ,用来在bean属性加载完毕时执行的方法。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
TransactionTemplate的2个接口的impl方法做了什么?
afterPropertiesSet如下
// 只是校验了事务管理器不为空
@Override
public void afterPropertiesSet() {
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
execute方法如下
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
//TODO 创建事务 (与声明事务调用同一个方法)
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
// 2.执行业务逻辑,这里就是用户自定义的业务代码。如果是没有返回值的,就是doInTransactionWithoutResult()。
result = action.doInTransaction(status);
} catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
// 应用运行时异常/错误异常 -> 回滚,调用AbstractPlatformTransa