1.事务
在学习数据库时,已经接触过这个概念,事务指的是一组操作的集合,是一个不可分割的操作.事务会把所有的操作作为一个整体,一起向数据库提交或者撤销操作,这组操作要么同时成功,要么同时失败.事务的操作主要有三步,1.开启事务 start transaction/begin(一组操作开启事务) 2.提交事务:commit(这组操作全部成功,提交事务) 3.回滚事务:rollback(这组操作中间出现任何一个异常,回滚事务).
2.Spring中事务的实现 Spring中的事务操作分为两类:1.编程式事务(手动写代码操作事务) 2.声明式事务(利用注解自动开启和提交事务),在数据库中,建立下面的表:分为用户表和日志表,用户注册时在日志表中插入一条数据.分别建立对应的类和mapper层,service层,controller层.Controller层的代码如下:
Service层的代码如下:
mapper层的代码如下:
下面介绍Spring中的声明式事务@Transactional,在需要事务的方法上添加@Transactional注释就可以实现.正常情况下,传入name和password
查看数据库,发现插入正常.
现在修改程序使之出现异常,出现异常后,数据库就不能新增用户信息.
这里设置一个算数异常,在没有添加@Transactional的情况之下,即时发生异常,数据还是会插入.
这里抛出了异常,查看数据库还是插入了数据
这里就需要使用@Transactional.@Transactional的作用:@Transactional可以用来修饰方法或者类:修饰方法时:只有修饰public方法才会生效(修饰其他方法时不会报错,也不生效);修饰类时:对@Transactional修饰的类中的所有的public方法都生效.方法/类被@Transactional注释修饰时,在目标方法开始执行之前,会自动开启事务,方法执行结束之后,会自动提交事务.如果在方法执行过程中,出现异常,且异常未被捕获,就进行事务的回滚操作.如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务.修改上述代码,再一次进行测试,观察用户信息是否会被写入数据库.
这里没有进行异常捕获和抛出,所以会进行回滚,Spring的事务管理依赖于未被捕获的异常来触发回滚机制.这里对异常进行捕获,
注册一个名为boluo的用户,可以发现,虽然程序出错了,但是由于异常被捕获了.依旧可以成功写入数据库
在对异常进行捕获之后,如果需要事务进行回滚,有下面两种方式:1.重新抛出异常
2.手动回滚事务,如下:
3.Transactional详解.@Transactional注解当中的三个常见的属性:
1.rollbackFor:异常回滚属性.指定能够触发事务回滚的异常类型,可以指定多个异常类型. 2.lsolation:事务的隔离级别.默认值为Isolation.DEFAULT 3.propagation:事务的传播机制,默认值为Propagation.REQUIRED
3.1 rollbackFor @Transactional默认只在遇到运行时异常和Error时才会进行回滚,非运行时异常不回滚.即Exception的子类中,除了RuntimeException以及子类.这里设置一个IO异常
插入一个名为fanqieyu的用户,查看数据库,由于IO异常既不属于RuntimeException和Error.所以不会进行事务的回滚.
如果这里要设置将所有的异常都进行回滚,需要配置@Transactional中的rollbackFor属性,通过rollbackFor这个属性指定出现何种类型的异常时进行事务的回滚.
当然也可以这样设置
rollbackFo会在默认的基础上增加指定的回滚类型. 结论:在Spring的事务管理中,默认只在遇到运行时异常RuntimeException和Error时来会进行回滚.如果需要回滚指定类型的异常,可以通过rollbackFor属性来指定. 3.2事务的传播机制 事务的传播机制就是:多个事务方法存在调用关系时,事务是如何在这些方法之间进行传播的,比如有两个方法A,B都被@Transactional修饰,A方法调用B方法,A方法运行时会开启一个事务,当A调用B时,B方法本身也有事务,此时B方法运行时,是加入A的事务还是新建一个事务呢?这个就涉及到了事务的传播机制.一个公司的流程管理,执行任务之前,需要先写执行文档,任务执行结束,再写总结报告.A,B部门的流程相同:
这里A有一项工作,需要B的帮助,此时B是直接使用A的文档还是新建一个文档呢?事务传播机制解决的是一个事务在多个方法中传递的问题
这里主要介绍两种事务的传播机制:1.REQUIRED(默认值) 2.REQULIRES_NEW 1.REQUIRED(加入事务),@Transactional注解支持事务传播机制的设置,通过propagation属性来指定传播行为.Propagation.REQUIRED:默认的事务传播机制,如果当前存在事务,则加入事务.如果当当前没有事务,则创建一个事务.下面的例子,用户注册,插入一条数据,记录操作日志,插入一条异常数据.
这个流程,访问p1,开启一个事务,先执行userService的方法,执行成功(和p1使用的是一个事务),记录操作日志,插入一条数据(出现异常,执行失败)(由于这里已经有事务了,则加入这个事务),因为日志这里出现了异常,由于日志和插入用户数据这里使用的是一个事务,所以都会发生回滚.
2.REUQIRES_NEW(新建事务),Propagation.REQUIRES_NEW:创建一个新的事务.如果当前存在事务,则把当前事务挂起,也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的方法都会新开启自己的事务,且开启的事务互相独立,互不干扰,将上述UserService和LogService中相关方法事务传播机制改为Propagation.REQUIRES_NEW这里发生异常之后,由于这里设置为了新建事务,所以PropagationController.r3()事务:因为异常传播回滚.UserService.insertUser()事务:因运行时异常回滚 LogService.insertLog()事务:不会回滚,因为在调用UserService.insertUser()时就发生了异常,所以没有执行到 LogService.insertLog(),所以没有创建事务,也就谈不到回滚了.