都要面试了还不来学学mysql事务隔离机制?

大家有没有想过一个问题,我们为什么需要事务?事务解决了怎样的问题?事务又会带来什么新的问题?本人也是带着疑惑一步步去深入学习,特此总结一下。

一、基础概念

1.1 什么是事务?

事务(Transaction) 是访问和更新数据库的程序执行单元,事务中可能包含一个或多个SQL语句。事务最大的特点就是,要么SQL语句都执行,要么都不执行。

1.2 事务条件

事务必须总是满足以下的四个条件:

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

以上四个条件简称ACID,下文将对事务条件逐一进行讲解。

1.2.1 原子性

用一个最简单的案例来说:

张三李四张三给李四转账100元张三余额应该减100元李四余额应该加100元张三李四

上面这个转账操作,可以分为三条sql语句:

  1. 查询张三余额是否>100元,若满足则执行后续SQL,否则返回。
  2. 张三余额减去100元
  3. 李四余额加100元

在这个案例当中,我们应该确保上面的转账操作要么都成功进行,要么都失败,才能确保交易的合法性,即就是事务不会结束在书屋中间某个环节,如果在事务的执行过程中发生错误,则会回滚到事务开始的状态。即满足了事务的 原子性条件。

1.2.2 一致性

事物的一致性有点难理解,至少对于我是这样的,而在我搜集很多资料总结的时候,我看到了这么一句话:事务一致性是:应用系统从一个正确的状态到另一个正确的状态,我瞬间恍然大悟了。一致性关注数据的可见性,中间状态的数据对外部不可见,只有最初状态和最终状态的数据对外可见。

1.2.3 隔离性

多个用户访问数据库时,各自的事务具有隔离性,每个事务都有自己的数据空间,不会相互干扰。

1.2.4 持久性

执行事务提交后,数据会永久性保留在硬盘中。

二、事务隔离级别

mysql 8.0+可以查看当前隔离级别:

select @@transaction_isolation;

以前的老版本查看隔离级别是:

select @@tx_isolation;

mysql事务隔离级别分为以下四种:

事务隔离级别 脏读 不可重复读 幻读
读未提交 (read-uncommitted)
读已提交 (read-committed)
可重复读 (repeatable-read)
串行化 (serializable)

名词解释:
脏读:事务A和事务B同时执行,此时事务A还没有提交修改的数据,但是事务B读取到事务A改变后的数据,这就是脏读。
不可重复读:事务A读取一条记录,此时事务B对该数据 进行了操作(改变了原数据)并提交事务B,此时事务A再次查询数据与第一次读取的不一样,这就是不可重复读(两次读取的不一样啊,就是说重复读的话可能会前后矛盾,所以可以理解成不可重复读。)。
幻读:事务A、B同时开启,若数据库此时有两条数据(id分别是1,2),事务B此时插入了一条数据(id为3),同时提交事务B,此时事务A再插入id为3的数据的时候,会提示插入失败,但是查询数据依然只能查到两条数据,这就是幻读。
不可重复读重点在于update和delete,而幻读的重点在于insert
在进行介绍之前,我们首先创建一个测试表。

CREATE DATABASE study; 
use stydy;
CREATE TABLE person(
		name varchar(20),
		country varchar(20),
		salary decimal,
		id int (11) primary key auto_increment
		);
insert into person(id,name,salary,country) values(1,"小王",1000,"中国");

2.1 读未提交

读未提交可能会出现脏读、不可重复读、幻读。
(a)脏读

脏读:若同时有多个事务A,B开启,事务B改变了数据但是没有提交,但此时事务A中可以读到事务B中未提交的数据。若此时B事务回滚,则出现了脏读。

我们先来开启两个事务:

事务A 事务B
set session transaction isolation level read uncommitted; set session transaction isolation level read uncommitted;
start transaction; start transaction;
select *from person;
在这里插入图片描述
update person set salary=2000 where name=“小王”;
select *from person; 在这里插入图片描述
commit; commit;

可以看到,事务B未提交,但是已经影响了事务A,所以这就是脏读。

2.2 读已提交

读已提交不会出现脏读,但是还是会带来不可重复读和幻读。
(a)不可重复读:

若同时有多个事务A,B开启,事务A先读取一次数据,事务B改变了数据并提交事务B,此时事务A再读取数据就是被事务B更新过的值,与第一次读取的结果不一致,这就是不可重复读。

我们先来开启两个事务:

事务A 事务B
set session transaction isolation level read committed; set session transaction isolation level read committed;
start transaction; start transaction;
select *from person;
在这里插入图片描述
update person set salary=2000 where name=“小王”;
select *from person;
可以看到已经解决了脏读在这里插入图片描述
commit;
select *from person;在这里插入图片描述
commit;

可以看到解决了脏读,但是还是会出现读取结果前后不一致的情况。即就是不可重复读。

2.3 可重复读

(a)幻读

两个事务同时开启的时候,若一方对数据库insert数据,则会出现幻读!

我们先来开启两个事务:

事务A 事务B
set session transaction isolation level repeatable-read; set session transaction isolation level repeatable-read;
start transaction; start transaction;
select *from person;
在这里插入图片描述
update person set salary=2000 where name=“小王”;
select *from person;
可以看到已经解决了脏读在这里插入图片描述
commit;
select *from person;
可以看到已经解决了不可重复读 在这里插入图片描述
start transaction;
insert person(id,name,salary,country) values(0,“小张”,5000,“加拿大”);
commit;
insert person(id,name,salary,country) values(0,“小张”,5000,“加拿大”);在这里插入图片描述
select * from person;
出现了幻读,明明只有一条数据还是插入失败? 在这里插入图片描述
commit;

2.4 串行化隔离级别

事务隔离级别设置为串行化时,如果同时开启多个事务,为保证其他事务不会幻读到这个数据,insert数据时会“卡住”,直到其他事务提交。insert才可以执行完成添加操作,这样即就解决了幻读问题!

总结:

以上例子说明了事务隔离级别不同可能会带来不同的结果,另外事务隔离级别为串行化时,读写数据都会锁住整张表,隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。因为这个并不常用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章