Spring事务和事务传播机制
1.事务的定义2.Spring中的事务实现3.Spring声明式事务(自动事务)4.事务特性5.事务隔离级别6.举例说明事务的读未提交---脏读7.举例说明事务读已提交---不可重复读8.举例说明事务可重复读---幻读9.Spring事务传播机制10.事务传播机制--propagation.required 支持当前事务11.事务传播机制--不支持当前事务-(propagation.never)12.事务的传播机制--不支持当前事务(propagation.requires_new)1.事务的定义
将一组操作封装成一个执行单元,要么全部成功,要么全部失败。
2.Spring中的事务实现
Spring中的事务操作分为两类:
1.手动操作事务;
2.声明式自动提交事务.
3.Spring声明式事务(自动事务)
声明式事务的实现很简单,在方法上添加@Transactional注解就可以实现了,无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果重土发生了没有处理的异常就会自动回滚事务。
举例说明:在方法上面添加@Transactional之后,就开启了事务,当往数据库进行添加操作的时候,int num=10/0,添加功能不会完成。
如果没有添加@Transactional注解,运行到int num=10/0的时候,虽然会报错,但是往数据库添加内容的操作可以完成。>无论是否加注解@Transactional,当执行int num=10/0的时候,都会报错。
try catch导致事务失效,
针对事务失效有以下的解决方式:
(1)将catch的异常抛出去---------throw e
2.在catch使用代码手动进行事务的回滚操作
4.事务特性
1.事务有四大特性:原子性、持久性、一致性、隔离性。
a)原子性:一个事务中的所有操作,要么全部完成,要么全部不完成。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
b)一致性:在事务开始之前和事务结束之后,数据库的完整性没有被破坏。
c)持久性:事务处理结束后,对数据的修改是永久的,即便系统故障也不会丢失。
d)隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行由于交叉执行而导致数据的不一致。
2.事务隔离分为不同级别:包括读未提交、读提交、可重复读、和串行化
5.事务隔离级别
1.为什么要设置事务的隔离级别?
设置事务的隔离级别是用来保障多个并发事务执行更可控,更符合操作者预期的。
2.查看数据库的全局事务隔离级别和客户端事务隔离级别。
select @@global.tx_isolation,@@tx_isolation
更改事务隔离级别
set session transaction isolation level read committed
再次查看数据库的全局事务隔离级别和客户端事务隔离级别。
发现,客户端事务隔离级别由repeatable-red变成了read-committed。
3.MySQL事务隔离级别由四种:
1.read uncommitted:读未提交,该隔离级别的事务可以看到其他事务未提交的数据,该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此,将该级别读到的数据称为脏数据(脏读)
2.read committed:读已提交,该隔离级别的事务可以读取到已经提交到的数据,因此不会有脏读的问题,由于在事务的执行中可以读取到其他事务提交的结果,在不同时间的相同的SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
3.repeatable read:可重复读,是MySQL的默认事务级别,它能确保同一事务多次查询的结果一致,但是,也会有新的问题,比如,此级别的事务正在执行时,另一个事务成功的插入了某条数据,但是因为它每次查询的结果都是一样的,所以,会导致查询不到这条数据,自己重复插入的时候又失败。在事务中查询不到这条信息,但是自己就是插入数据失败,这种情况叫做幻读。
4.serializable:序列化,事务最高隔离级别,他会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,因为执行效率比较低,真正使用的场景不多。
4.Spring事务隔离级别有五种:
除了MySQL的四种事务隔离级别之外,
Spring事务隔离级别有一种:isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
5.总结
MySQL中有4种事务隔离级别:
1.读未提交(存在脏读/不可重复读/幻读的问题);
2.读已提交(存在不可重复读/幻读问题);
3.可重复读(存在幻读的问题)可重复读是MySQL默认的事务隔离级别;
4.序列化;
5.脏读是读到了其他事务未提交的数据;
6.不可重复读是读到了其他事务修改的数据;
7.幻读是读取到其他事务新增或删除的“幻象”数据。
6.举例说明事务的读未提交—脏读
1.首先将数据库的隔离级别由原本默认的repeatable read 改成read uncommitted
2.创建数据库city,并且创建数据表city
3.再重新开一个mysql,然后,开启事务,往city表中添加数据,然后第一个mysql窗口查数据表中的信息,此时是可以读取到数据表中的信息,第二个mysql窗口针对添加数据的操作进行回滚,第一个mysql窗口再次查数据表中信息的时候,就读取不到刚刚的添加信息,此时,就表示发生了回滚。
7.举例说明事务读已提交—不可重复读
1.将事务隔离级别由 可重复读—>读已提交
2.数据不可重复读:不同时间相同Sql语句所查出的结果不同。读到了其他事务修改的数据。
8.举例说明事务可重复读—幻读
1.将事务隔离级别改成repeatable read;
2.幻读是读取到其他事务新增或删除的“幻象”数据。
9.Spring事务传播机制
1.事务传播机制是什么?
事务传播机制的定义: 指的是Spring中多个事务在相互调用时, 他们之间的行为方式是如何执行的。
2.为什么需要事务传播机制?
事务隔离级别是保证多个并发事务执行的可控性(稳定性),而事务传播机制是保证一个事务在多个调用方法间的可控性(稳定性)。
3.Spring事务传播机制包含七种:
1.propagation.required:默认的事务传播级别,它表示如果当前如果存在事务,就加入事务,如果当前没有事务,就创建一个事务。
2.propagation.supports:如果当前存在事务,就加入事务,如果当前没有事务,就以非事务的方式继续运行。
3.propagation.mandatory(mandatory:强制性)如果当前存在事务就加入事务,如果当前没有事务,就抛出异常。
4.propagation.requires_new:表示创建一个新的事务,如果当前存在事务,就把当前事务挂起。不管外部方法是否开启事务,propagation.requires_new修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
5.propagation.not_supported:以非事务方式运行,如果当前存在事务,就把当前的事务挂起。
6.propagation.never:以非事务的方式运行,如果当前存在事务,则抛出异常。
7.propagation.nested:如果当前存在事务,创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则取值等价于propagation_required.
4.嵌套事务nested和加入事务required的区别:
1.整个事务如果全部执行成功,二者结果是一样的;
2.如果事务执行到一半失败了,加入事务:整个事务会全部回滚;而嵌套事务会局部回滚,不会影响到上一个方法中执行的结果。
10.事务传播机制–propagation.required 支持当前事务
1.创建log日志表:
创建user用户表:
2.在TestController类当中加上一个总事务,事务传播机制为:propagation.required,在这个类当中调用InsertUserServcie类当中的方法和InsertLogService类当中的方法,这两个类当中的方法设置的事务传播机制为:propagation.required。
运行结果:两个数据表中的数据都插入数据成功。
当调用类(两个类)中的其中一个类执行错误,则整个回滚。
代码会报错
查看数据库:
发现:数据没有发生变化
结论:propagation.required事务传播机制的特点是:一个类调用另外两个类的时候,被调用类(一个类)当中有事务,调用类(其他两个类)如果存在事务,就加入,如果调用类中出现了错误,就全部回滚,如果没有出现错误,就添加成功。如果不存在事务,就创建一个事务。
11.事务传播机制–不支持当前事务-(propagation.never)
propagation.never:一个类调用另外两个类的时候,当被调用类没有设置事务传播机制的时候,调用类设置事务传播机制为不支持当前事务(propagation.never),以非事务的方式运行,如果当前存在事务,则抛出异常。
1.当主调用方法事务的传播机制没有设置的时候。
2.当两个被调用的方法,事务传播机制设置为:propagation.never的时候,
3.当运行代码的时候,就会报错,因为propagation.never是以非事务方式运行的如果当前存在事务就会抛出异常,并且数据库中的数据也不会增加。
12.事务的传播机制–不支持当前事务(propagation.requires_new)
propagation.requires_new:不支持当前的事务,重新创建事务。
1.主调用方法不设置事务的传播机制类型;
2.另外两个被调用的方法设置事务的传播机制类型为propagation.requires_new;
3.可以观察到,因为propagation.requires_new,不支持当前的事务,重新创建事务,所以两个被调用方法重新创建各自的事务,互不影响,所以,当insertLogService方法中出现了10/0这样的错误的时候,inserLogService方法会被中断,而insertUserService方法不会受到影响。
insertLogService方法会报错