mysql-事务隔离级别超级详细 解读

前言:
我:数哥,数据库的 事务 知道不?
数哥:这你都不知道?
我:。。。。。。!
数哥:不就是,RU,RC,RR,Serializable
我:都解决了什么问题啊?
数哥:那我哪知道?
我:不知道了吧,解决了:脏读、不可重复读、幻读
在这里插入图片描述

mysql-事务隔离级别超级详细 解读

1、事务

1.1百科定义:

​ 数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位

1.2事务性质(ACID)
  1. 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。

  2. 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。

  3. 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。

  4. 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障

**note:**事务的ACID特性是由关系数据库系统(DBMS)来实现的,DBMS采用日志来保证事务的原子性、一致性和持久性;事务的隔离性,DBMS是采用锁机制来实现的

1.3事务类型
1.3.1显式事务

显式事务又称自定义事务,是指用显式的方式定义其开始和结束的事务,当使用start transaction和 commit语句时则表示发生显式事务。

1.3.2隐式事务

隐式事务是指每一条数据操作语句都自动地成为一个事务,事务的开始是隐式的,事务的结束有明确的标记。即当用户进行数据操作时,系统自动开启一个事务,事务的结束则需手动调用 commit或 rollback语句来结束当前事务,在当前事务结束后又自动开启一个新事务。

1.3.3自动事务

自动事务是指能够自动开启事务并且能够自动结束事务。在事务执行过程中,如果没有出现异常,事务则自动提交;当执行过程产生错误时,则事务自动回滚。

1.4 事务控制
-- 开启事务
start transaction ;

-- 业务逻辑操作

-- 回滚事务
rollback;

-- 提交事务
commit ;

2、脏读、不可重复读、幻读

2.1 脏读

脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据,这个数据相对A来说 就是脏数据;

2.2 不可重复读

同一个事务中,根据同一个条件进行多次查询,结果不一样,就是不可重复读(主要针对 更新

2.3 幻读

幻读是指同一个事务内多次查询返回的结果集(结果数量)不一样(比如增加了或者减少了行记录),主要针对 新增和删除

3、隔离级别

3.1 Serializable(串行化):
3.1.1 作用:

可避免脏读、不可重复读、幻读情况的发生。

3.1.2 开启命令

set session transaction isolation level Serializable;

3.2 Repeatable read(可重复读):
3.2.1 作用

可避免脏读、不可重复读情况的发生。

3.2.2 开启命令

set session transaction isolation level repeatable read;

3.3 Read committed(读已提交):
3.3.1 作用

可避免脏读情况发生。

3.3.2 开启命令

set session transaction isolation level read committed;

3.4 Read uncommitted(读未提交):
3.4.1 作用

最低级别,以上情况均无法保证。

3.4.2 开启命令

set session transaction isolation level read uncommitted;

查看隔离级别指令

-- mysql8.0 以后
select @@transaction_isolation;

-- mysql版本 8.0 之前
select @@tx_isolation;

4、源码

注意一下测试方便,模拟多线程,开启两个session(分别开启事务A 和 B),方便操作,两个session 都开启相同的隔离级别

(A 负责 查询)(B负责

4.1 read uncommitted
  • 4.1.1 启动()
    set session transaction isolation level read uncommitted;

  • 4.1.2 起始状态

select *
from user
where id = 1;

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |
  • 在B进行更新(不提交事务
-- 开启事务
start transaction ;
-- 更新数据
update user
set name = '1'
where id = 1;
  • A中 查询结果
select *
from user
where id = 1;

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 1    | 1        | 1    |  1.0000 |

很明显,A结果已经变成了 1,读到了B 事务未提交的 修改结果;如果B 回滚 这就是无效数据;

这就是脏读

4.2 Read committed
  • 4.2.1 启动
    set session transaction isolation level read committed;

  • 4.2.2 起始状态

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |
  • 在B 进行更新(不提交事务
-- 开启事务
start transaction ;
-- 更新数据
update user
set name = '1'
where id = 1;

commit;
  • A中 查询结果
select *
from user
where id = 1;

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |

很明显,S结果已经变成了 1,读到了B 事务未提交的 修改结果;

这就解决了脏读 的问题;

B 事务提交后 ,A事务再次查询

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 1    | 1        | 1    |  1.0000 |

A事务 的两次操作 查询结果不一致,这就是一次事务 不可重复读的问题

4.3 Repeatable read
  • 4.3.1 启动
    set session transaction isolation level Repeatable read;

  • 4.3.2 起始状态

+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |
  • A中 查询结果(A 事务不结束)
-- 开启事务
start transaction ;

select *
from user
where salt = 1;
+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |
  • 在B 进行更新(提交事务
-- 开启事务
start transaction ;
-- 更新数据
update user
set name = '1'
where salt = 1;

-- 提交事务
commit;

A事务 再次查询

select *
from user
where id = 1;
+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 11   | 1        | 1    |  1.0000 |

通过结果可以看到:A 事务中(一个事务中 两次查询的 结果一致了-解决了不可重复读的问题)

事务B先执行以下:

mysql> start transaction ;
Query OK, 0 rows affected (0.00 sec)

mysql> select *
-> from user
-> where salt <= 3;
+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 4    | 4        | 1    |  4.0000 |
|  2 | 2    | 2        | 2    |  2.0000 |
|  3 | 4    | 4        | 1    |  4.0000 |
|  4 | 4    | 4        | 1    |  4.0000 |
|  5 | 4    | 4        | 1    |  4.0000 |
|  6 | 4    | 4        | 1    |  4.0000 |
+----+------+----------+------+---------+
6 rows in set (0.00 sec)

事务A重新开启事务,并执行

mysql> start transaction ;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into user(id, name, password, salt, account) VALUES (7,4,4,1,4);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

事务B不提交再次查询

mysql> select * from user where salt <= 3;
+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 4    | 4        | 1    |  4.0000 |
|  2 | 2    | 2        | 2    |  2.0000 |
|  3 | 4    | 4        | 1    |  4.0000 |
|  4 | 4    | 4        | 1    |  4.0000 |
|  5 | 4    | 4        | 1    |  4.0000 |
|  6 | 4    | 4        | 1    |  4.0000 |
+----+------+----------+------+---------+
6 rows in set (0.00 sec)

事务B 提交后 再次查询

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user where salt <= 3;
+----+------+----------+------+---------+
| id | name | password | salt | account |
+----+------+----------+------+---------+
|  1 | 4    | 4        | 1    |  4.0000 |
|  2 | 2    | 2        | 2    |  2.0000 |
|  3 | 4    | 4        | 1    |  4.0000 |
|  4 | 4    | 4        | 1    |  4.0000 |
|  5 | 4    | 4        | 1    |  4.0000 |
|  6 | 4    | 4        | 1    |  4.0000 |
|  7 | 4    | 4        | 1    |  4.0000 |
+----+------+----------+------+---------+
7 rows in set (0.00 sec)

我们会发现,what? 说好的 **“幻读”**呢;

其实这里 单纯的隔离级别RR ;不能解决 的问题,之所以 没有这个问题 ,是因为 mysql的 MVCC 机制

4.4 Serializable

这种隔离级别 不做 过多赘述,没有 幻读问题,但是 大大较低了 性能;

个人水平有限,如有问题,欢迎大家留言指出,虚心接受,及时更正

如果大家觉得,还可以,烦请点赞收藏,谢谢

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值