之前就在后盾的 dao 层留神到,根本对数据库进行删除和编辑的操作都会加上 @Transactional 注解(如下),过后只是大略明确是进行事务回滚的。然而也不太分明具体的执行过程,以前具体应用场景。于是搜寻了相干材料来了解并记录一下。
@Modifying
@Transactional
void deleteAllByDistrictId(Long districtId);
@Transactional 简略概括
应用这个注解的类或者办法的事务由 spring 解决,即是办法外面对数据库操作,如果失败则 spring 负责回滚操作,胜利则提交操作。也就是上周学长提到的保障事务的原子性:对数据进行操作的时候,要么全都执行,要么全都不执行。
举个例子:以后办法须要将数据插入两个数据表:
如果第一张表插入胜利了,然而插入第二张的时候失败了,怎么解决?
1. 要么就保障两张表都插入胜利
2. 要么就进行回滚,勾销对第一张表的操作。
@Transactional 注解就是为了帮忙咱们治理这些事务。
AOP
查找材料的时候我发现这么一句话:
@Transactional 原理是基于 spring aop 实现的。
那么 Aop 又是什么呢?
AOP(Aspect-oriented programming):面向切面編程。
这种在 运行时,动静地将代码切入到类的指定办法、指定地位上 的编程思维就是面向切面的编程。
与之绝对是的以前常应用的 OOP (Object-oriented programming) 面向对象
上面用一个场景来阐明一下应用Aop 带给咱们的益处:
场景 :如果说咱们曾经实现了一个我的项目, 当初想退出日志性能,在 save 办法中打印日志。
- 如果咱们仍然应用 OOP 面向对象,那么咱们会这么做:在 save 办法代码里,写上打印日志的的代码。有时候写错时甚至会导致原来执行失常的办法执行失败。
-
如果咱们应用了 AOP 呢?
@Around("execution(* Controller.save(..))") public void print() throws Throwable {
咱们就能够应用切面,当 Controller.save 执行的时候,执行该打印日志的函数。
这样的做法,对原有代码毫无入侵性 ,这就是 AOP 的益处了, 把和主业务无关的事件,放到代码里面去做。
切面执行机会有五种:
「@Before」: 在指标办法调用前去告诉
「@AfterReturning」: 在指标办法返回或异样后调用
「@After」: 在指标办法返回后调用
「@AfterThrowing」: 在指标办法异样后调用
「@Around」: 将指标办法封装起来,本人确定调用机会
在理解 AOP 是啥之后,咱们再来看看实现原理:
AOP 实现次要分为两类:
1. 动态 AOP
2. 动静 AOP
这里咱们次要讲动静 AOP,因为spring 中 AOP 的实现是就说通过动静代理实现的。
什么是代理呢,就是我再生成一个代理类,去代理 Controller 的 save()办法,代码大略就长这样:
class ControllerProxy {
private Controller controller;
public void save() {controller.save();
print() // 打印日志}
}
所以在方才那张图中,spring 实现 AOP 过程大略是这样的:
(这里依据不同的切面机会过程略有不同,这里是 After 切面)
Spring AOP 就是基于动静代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会应用 JDK Proxy,去创立代理对象。
@Transactional
@Transactional 原理就是基于 spring aop 实现的。
依据 AOP, 咱们就能够大略猜测出 @Transactional 的执行过程,这里以 delete 办法作为事务例子:
大略理解 @Transactional 执行逻辑之后,
那么咱们来看看 @Transactional 什么时候会回滚 呢?
先来看看 异样的分类
一个个来说,对于加了 @Transactional 的办法或类:
Error: 肯定会回滚
Excepion: 分为两类
-
不可查的异样(unchecked exceptions):RuntimeException 及其子类和谬误(Error)
RuntimeException 的子类有很多,不只图片上的,相似的有 ArithemticeExcepiton,算术运算异样等。
须要留神的是:
Spring 框架的事务基础架构代码将默认地 只在抛出 error 时和 unchecked exceptions 时才标识事务回滚 。
如果在事务中抛出其余类型的异样,但却 冀望 Spring 可能回滚事务,就须要指定 rollbackFor 属性。@Transactional(rollbackFor = Exception.class)
- 可查的异样(checked exceptions):Exception 下除了 RuntimeException 外的异样,不会回滚。
例如,SQLException, 数据库连贯异样,IOException, 编译异样。
对于这种 IOException、SQLException 等以及用户自定义的 Exception 异样,
JAVA 编译器强 制要求咱们必须对呈现的这些异样进行 catch 并解决,否则程序就不能编译通过。
所以,面对这种异样不论咱们是否违心,只能本人去写一大堆 catch 块去解决 可能的异样。
这一点我深有体会:
上次因为写了 formatter.parse(), 编译器就提醒必须 throws ParseException, 并且调用它的函数也须要 throws ParseException。
文章到此结束,若有谬误还请斧正