事务控制的3种方式
编程式事务 :直接在代码里手动开启事务,手动提交,手动回滚 。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了 。声明式事务 :就是使用Spring Aop配置事务 ,这种方式简化了编码。需要注意的是切入点表达式一定要写正确。注解事务 :直接在Service层的方法上面加上@Transactional注解 ,最简单方便的方式。
伪代码
排序往后的方法报错,导致排序前的方法不回滚 ,如下:updataFlag 方法出错,analyseRedBall 和 analyseBlueBall 方法不会回滚
public void statistics() {
analyseRedBall(periods, redBalls);
analyseBlueBall(periods, blueBalls);
updataFlag(periods);
}
为什么不会滚呢
Spring默认情况 下是捕获到方法的RuntimeException 异常,也就是说只要属于RuntimeException 异常或及其子类 都能回滚。不属于运行时异常时,事务不回滚的。
解决方案
声明式事务
确保切入点表达式 书写正确,如在配置里面添加rollback-for
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
注解事务
使用位置
类上 :该类的所有 public 方法 将都具有务属性方法上 :只能应用到 public 方法上,这是由Spring AOP的本质决定的,如果在 protected、private 或者默认可见性的方法上 使用 @Transactional 注解,将被忽略,也不会抛出任何异常。接口、接口方法上 :接口实现类或接口实现方法可继承事务属性,Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效
基本用法
将Spring默认的RuntimeException 异常修改为Exception 异常,可以保证任何异常都可以回滚。
@Transactional(rollbackFor = Exception.class)
或指定多个异常
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
如上述实例修改为
@Transactional(rollbackFor = Exception.class)
public void statistics() {
analyseRedBall(periods, redBalls);
analyseBlueBall(periods, blueBalls);
updataFlag(periods);
}
异常抛出
在catch语句中抛出异常 ,以便让Aop捕获异常执行回滚事务 ,如下伪代码
@Transactional(rollbackFor = Exception.class)
public void statistics() {
analyseRedBall(periods, redBalls);
analyseBlueBall(periods, blueBalls);
updataFlag(periods);
}
public void analyseRedBall(List<Period> periods, List<RedBall> redBalls) {
try {
} catch (Exception e) {
throw new RuntimeException();
}
}
手动事务
配合事务注解@Transactional ,手动处理事务回滚
设置回滚代码
在catch语句中设置回滚代码 来实现回滚,此方法在抛出异常后也能return 返回值,适合需要拿到返回值的场景
@Transactional(rollbackFor = Exception.class)
public boolean statistics() {
try {
analyseRedBall(periods, redBalls);
analyseBlueBall(periods, blueBalls);
updataFlag(periods);
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return fales;
}
return true;
}
设置回滚点
Object o = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(o);
存储引擎
到此之前,代码无误,那为什么 Spring 或 SpringBoot 的事务回滚还是没有任何效果呢?
数据库肯定是MySQL ,那表的存储引擎,也要支持事务安全才行 ,最重要,也是最多人忽视的地方
InnoDB 和 BDB 提供事务安全表,其他存储引擎都是非事务安全表
注:Oracleb不存在存储引擎的概念 ,数据处理大致可以分成两大类:联机事务处理OLTP (on-line transaction processing)、联机分析处理OLAP (On-Line Analytical Processing)。
- OLTP是
传统的关系型数据库 的主要应用,主要是基本的、日常的事务处理,例如银行交易。强调数据库内存效率,强调内存各种指标的命令率,强调绑定变量,强调并发操作 - OLAP是
数据仓库系统 的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。强调数据分析,强调SQL执行市场,强调磁盘I/O,强调分区等
|