目录
一、什么是事务
二、事务的操作
三、Spring下实现事务
1、Spring编程式事务
(1)事务提交
(2)事务回滚
2、Spring声明式事务
(1)无异常--提交
(2)异常且不捕获--回滚
(3)异常且捕获--提交
四、异常捕获后进行回滚
1、再次抛异常--回滚
2、手动进行回滚--回滚
五、@Transactional注解常见三个属性
1、rollbackFor
2、Isolation
3、propagation
一、什么是事务
事务是一个不可分割的操作。事务会把一些列操作看做一个整体提交给数据库,要么全部执行成功,要么出现异常全部撤回不执行。例如:A向B转100元,此时A账号-100,B账号+100,修改数据库时,对这两个操作就要求要求全部成功或全部失败。
二、事务的操作
开启事务、提交事务(全部成功)、回滚事务(全部失败)。
三、Spring下实现事务
用户表注册账号,使用事务实现。准备工作:用户表、实体类、建立数据库连接。
1、Spring编程式事务
(1)事务提交
DataSourceTransactionManager:事务管理器,用来获取事务(getTransaction)、提交事务(commit)、回滚事务(rollback);
TransactionDefinition:是事务的属性,在获取事务的时候,需作为参数,从而获取到一个事务;
TransactionStatus:事务的状态,提交和回滚。
当事务是提交时,数据库插入成功。
(2)事务回滚
事务进行了回滚,虽然提醒插入成功,但数据库没有插入的结果。
2、Spring声明式事务
以上需要获取事务、提交事务、回滚事务,比较繁琐。当加上@Transactional注解之后,就自动获取事务,没有异常或异常已进行捕获自动提交事务,有异常且未进行捕获就回滚事务。
(1)无异常--提交
(2)异常且不捕获--回滚
事务进行了回滚,虽然提醒插入成功,但数据库没有插入的结果。
(3)异常且捕获--提交
四、异常捕获后进行回滚
上述出现异常后,如若进行了捕获,事务还是会提交。如何在异常捕获后进行事务回滚???
1、再次抛异常--回滚
2、手动进行回滚--回滚
五、@Transactional注解常见三个属性
1、rollbackFor
rollbackFor:异常回滚属性,指定能够触发事务回滚的异常类型,可以指定多个异常类型。
@Transactional注解默认只有运行时异常和Error时才会进行回滚,其他异常不会回滚。
例如:
以上代码在运行时会抛出IOException异常,但事务依旧会提交,因为不是运行时异常。
若想所有异常都进行回滚,可以设置rollbackFor属性:
2、Isolation
Isolation:事务隔离级别。
(1)之前学习mysql的隔离级别:
①读未提交(可能出现脏读);②读提交(不可重复读);③可重复读(可能出现幻读)--mysql默认隔离级别;④串行化读。
(2)@Transactional注解的隔离级别:
①Isolation.DEFAULT:以连接的数据库的事务隔离级别为主;
②Isolation.READ_UNCOMMITTED:读未提交,可能出现脏读;
③Isolation.READ_COMMITTED:读已提交,不可重复读;
④Isolation.REPEATABLE_READ:可重复读,可能出现幻读;
⑤Isolation.SERIALIZABLE:串行化读。
(3)设置@Transactional注解的Isolation属性
3、propagation
propagation:事务的传播机制。
多个事务之间存在调用关系,事务如何进行传播的???
(1)Spring事务传播机制有7种:
①Propagation.REQUTRED:默认的事务传播机制,如果当前外部方法存在该事务,则内部方法加入该事务,如果当前外部方法没有事务,则内部方法创建一个新的事务。
例如:A方法中调用了B,若A方法有事务,则B不创建事务;若A方法没有事务,则B创建事务。若B中的某一个方法出现异常,则B的所有事务都回滚。
②Propagation.SUPPORTS:如果当前外部方法存在事务,则内部方法加入该事务;如果当前外部方法没有事务,则内部方法以非事务的方式继续运行。
例如:A方法中调用了B,若A方法有事务,则B不创建事务;若A方法没有事务,则B以非事务方式运行。若A存在事务且B中的一个方法出现异常,则B的所有事务都回滚。
③Propagation.MANDATORY:如果当前外部方法存在事务,则内部方法加入该事务;如果当前外部方法没有事务,则内部方法抛出异常。
例如:A方法中调用了B,若A方法有事务,则B不创建事务;若A方法没有事务,则抛出异常。
④Propagation.REQUIRES_NEW:无论外部方法是否存在事务,内部方法都会创建新的事务。且创建的事务之间互不打扰。
例如:A方法中调用了B,无论A是否有事务,B都会创建新的事务。
⑤Propagation.NOT_SUPPORTED:无论外部方法和内部方法是否存在事务,都将事务挂起,以非事务方式运行。
例如:A方法中调用了B,无论A和B是否有事务,最终都以非事务运行。
⑥Propagation.NEVER:以非事务方式运行,若外部或内部方法存在事务,则抛出异常。
例如:A方法中调用了B,若A或B存在事务,则抛出异常。
⑦Propagation.NESTED:若外部方法存在事务,则内部方法创建一个事务作为当前事务的嵌套事务来运行;如果当前外部方法没有事务,则内部方法创建一个新的事务。
(2)Propagation.REQUTRED和Propagation.NESTED的区别
共同点:若事务全部执行成功,二者没有区别;
不同点:若有部分事务抛出异常,Propagation.REQUTRED是加入外部方法的事务,会导致事务全部回滚;Propagation.NESTED嵌套事务,只会有部分回滚。嵌套事务进入之后相当于新建了一个保存点,而回滚时只回滚到当前保存点。
(3)设置@Transactional注解的propagation属性