MySql事务隔离级别和Spring传播机制

目录

一、事务隔离级别

1.1、事务的四要素(ACID)

1.2、并发所带来的问题

1.3、事务隔离级别类型

1.4、场景复现

1.4.1、脏读

1.4.2、不可重复读

1.4.3、幻读

二、Spring事务的传播机制


 


一、事务隔离级别

1.1、事务的四要素(ACID)

原子性:事务的所有操作都是原子性,即要不当前操作全部做完。如果中间操作失败,则回到最初的状态。即要不全做完,要不全不做。

一致性:事务开始前和事务开始后,数据库的完整性约束没有被破坏。

隔离性:同一时间,只允许一个事务操作同一个数据源。

持久性:事务完成后,对数据库的所有操作都会持久化到数据库中,不能回滚。

1.2、并发所带来的问题

脏读:事务A读取了事务B更新的数据,然后事务B又进行回滚。此时事务A读取到了脏数据。

不可重复读:事务A多次读取同一数据源出现结果不一致。如:事务B在事务A读取数据源过程中,对数据源进行了更新,导致事务A读取到数据不一致。主要出现在修改场景。

幻读:事务A在更新数据时,事务B又新增了一条新的记录,事务A提交之后发现新增之后的数据没有更新,出现幻读。主要出现新增或者删除等场景。

数据准备:

#表结构
CREATE TABLE `Class_Info` (
  `Id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `Name` varchar(11) DEFAULT NULL COMMENT '名称',
  `GradeId` int(11) DEFAULT NULL COMMENT '年级id',
  `HeadTeacher` varchar(11) DEFAULT NULL COMMENT '班主任',
  `AddTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `UpdateTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `Class_Info` (`Id`, `Name`, `GradeId`, `HeadTeacher`, `AddTime`, `UpdateTime`)
VALUES
	(1, '李四', 1, '1', '2021-03-23 19:28:44', '2021-03-23 19:28:44');
INSERT INTO `Class_Info` (`Id`, `Name`, `GradeId`, `HeadTeacher`, `AddTime`, `UpdateTime`)
VALUES
	(2, '张三', 1, '1', '2021-03-23 19:28:44', '2021-03-23 19:28:44');

(1)#设置会话事务隔离级别为读未提交
SET session TRANSACTION ISOLATION LEVEL Read uncommitted;

(2)#设置事务为不自动提交
set autocommit=0;

1.3、事务隔离级别类型

读未提交(Read Uncommitted):事务B可以读取事务A为已修改但是未提交的数据。该级别会出现脏读、幻读、不可重复读等现象。

读提交(Read Committed):事务B只能读取事务A提交之后的数据。该场景可出现幻读和不可重复读。不可重复读场景:事务A在B提交之前读取数据,接着在事务B提交之后又读取了数据,发现两次数据不一致。

不可重复读(Repeatable Read):保证一个事务不能读取另一个事务未提交的数据。该级别可能出现幻读场景。

1.4、场景复现

1.4.1、脏读

(1)开启事务 A
start transaction;

(2)#修改数据但不提交
update Class_Info set name='王五'  where id=1;

(3)#查询语句,发现Name已经变成更新之后的值为 '王五'
select *  from Class_Info where id=1;

(4)#回滚修改命令
rollback

(5)#查询语句,发现Name值为更新之前的值 '李四'
select *  from Class_Info where id=1;

结果分析:(4)查询语句在还未回滚之前查询到了(1)还未提交的数据,读取到了脏数据。

1.4.2、不可重复读

(1)#开启事务 A
start transaction;

(2)#查询表中所有记录
select * from Class_Info;


(4)开启事务 B
start transaction;

(5)表添加记录
INSERT INTO `Class_Info` (`Id`, `Name`, `GradeId`, `HeadTeacher`, `AddTime`, `UpdateTime`)
VALUES
	(3, '李逵', 1, '1', '2021-03-23 19:28:44', '2021-03-23 19:28:44');

(6)提交B事务
commit;

(7)事务接着查询表中所有记录
select * from Class_Info;

(8)提交事务 A 
commit;

结果分析:同一个事务中(2)和(7)同一个查询,发现查询的结果不一样,(7)中结果多了一条数据。

1.4.3、幻读

(1)#开启事务 A
start transaction;

(2)#将表中所有名字改为 祁东
update Class_Info set name='祁东'

(4)开启事务 B
start transaction;

(5)事务B添加记录
INSERT INTO `Class_Info` (`Id`, `Name`, `GradeId`, `HeadTeacher`, `AddTime`, `UpdateTime`)
VALUES
	(3, '李逵', 1, '1', '2021-03-23 19:28:44', '2021-03-23 19:28:44');

(6)提交B事务
commit;

(7)事务接着查询表中所有记录
select * from Class_Info;

(8)提交事务 A 
commit;

结果分析:发现结果事务A中本来已经修改所有的名字为祁东,但是由于事务B中间又添加了一条数据,造成出现幻读现象。

 

二、Spring事务的传播机制

PROPAGATION_REQUIRED(默认值):支持当前事务,如果不存在则新建一个事务;如果当前存在事务,则将加入当前事务,合并成一个事务。由于两个操作都在同一个事务中,因此若第二事务出现回滚操作,则整个操作都会回滚。

REQUIRES_NEW:新建事务,如果当前事务存在,则把当前事务挂起;此事务独立提交,即使父级事务异常,子事务还能正常提交。

NESTED:如果当前存在事务,则他变成父事务的子事务,方法结束后不直接提交,而是等事务全部结束后才提交;如果当前没有事务,则新建一个事务;如果异常,父事务可以捕获异常但是不会滚,会正常提交;如果父事务异常,则一定回滚。

SUPPORTS:如果当前存在事务,则加入到当前事务;如果不存在事务则以非事务的方式运行。

NOT_SUPPORTED:以非事务的方式运行;如果当前存在事务,则会把事务挂起;

MANDATORY(强制):如果当前存在事务,则在当前事务中运行;如果当前不存在事务则抛出异常,即父级方法必须有事务。

NEVER:以非事务的方式运行,即当前父级方法必须有事务,如果没有事务则会抛出异常。

总结:方法A为父方法,方法A中执行方法B

正常/异常PROPAGATION_REQUIREDREQUIRES_NEWNESTEDSUPPORTSNOT_SUPPORTEDMANDATORYNEVER
A正常、B正常A提交、B提交A提交、B提交A提交、B提交A提交、B提交A提交、B提交A提交、B提交A提交、B提交
A异常、B正常A回滚、B回滚A回滚、B提交A回滚、B回滚A回滚、B回滚A回滚、B提交A回滚、B回滚A提交、B提交
A异常、B异常A回滚、B回滚A回滚、B回滚A回滚、B回滚A回滚、B回滚A回滚、B提交A回滚、B回滚A提交、B提交
A正常、B异常A回滚、B回滚A提交、B回滚

A提交(捕获异常)、B回滚

A回滚(不捕获异常)、B回滚

A回滚、B回滚A提交、B提交A回滚、B回滚A提交、B提交
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值