之前就在后盾的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。
文章到此结束,若有谬误还请斧正