资讯专栏INFORMATION COLUMN

mysql事务隔离的一点理解

rubyshen / 1306人阅读

摘要:二事务隔离读未提交读已提交可重复读串行化读未提交隔离级别最低的一种事务级别,会发生脏读,不可重复读,幻读读已提交读到的都是别人提交后的值。

前言

先介绍一下事务的概念
事务(Transaction)就是数据库管理的一个逻辑单位,由一个有效的数据库操作序列构成。

事物ACID特性

原子性(Atomicity):事务作为一个整体被执行,要么全部成功执行,要么全部失败

一致性(Consistency):指的是逻辑上的一致性,即所有操作是符合现实当中的期望的

隔离性(Isolation):多个事务并发时,一个事务不应该影响其他事务的执行

持久性(Durability):被提交过的事务对数据库的修改应该永久保存在数据库中

通俗的理解,就是将一系列的数据库操作(增删改查)看做一个整体,要么所有操作都成功,要么都失败。

一、产生的问题

如果没有事务隔离的话,会发生以下的问题

1. 脏读

脏读是指一个事务读取了另一个事务未提交的数据

2. 不可重复读

不可重复读是指事务读取某行数据,多次读取的结果不同

不可重复读和脏读的区别:不可重复读是事务A读取某行数据后,事务B修改这行数据并提交之后,事务A再去读这行数据,读到了修改后的数据
3. 幻读

幻读是指事务A读某行数据后为100,事务B把这行数据改为99并提交,事务A查看这行数据,发现还是之前读取的100,但实际这行数据已经是99了,这就是幻读。
上面还有点不清晰,借鉴一下别人的白话解释

幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
二、事务隔离

Read uncommitted(读未提交)

Read Committed(读已提交)

Repeatable Reads(可重复读)

Serializable(串行化)

1. 读未提交

隔离级别最低的一种事务级别,会发生脏读,不可重复读,幻读

2. 读已提交

读到的都是别人提交后的值。这种隔离级别下,会引发不可重复读和幻读,但避免了脏读。

3. 可重复读

这种隔离级别下,会引发幻读,但避免了脏读、不可重复读。

4. 串行化

最严格的隔离级别。在串行化隔离级别下,所有事务按照次序依次执行。脏读、不可重复读、幻读都不会出现。

三、测试

下面我们在MYSQL下,来对上面四种事务隔离进行测试
在mysql中首先建立一张student表,有如下数据

学生id 学生姓名 学生性别
1 花轮
2 小丸子

看一下mysql的默认隔离级别

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.03 sec)

默认是可重复读,下面我们就来测试

1. 读未提交

首先开启事务A,读表中数据数据

mysql> begin;

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.02 sec)

打开另一个窗口,开启事务B,修改表中数据,不提交

mysql> begin ;

mysql> update student set sex="女" where id=1;
Query OK, 0 rows affected (0.00 sec)

再回到事务A中读表数据,看是否改变

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.01 sec)

可以发现在mysql下没有发生脏读。把上面两个事务进行回滚(rollback)操作

2. 读已提交

首先开启事务A,读表中数据数据

mysql> begin;

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.02 sec)

打开另一个窗口,开启事务B,修改表中数据,并提交

mysql> begin ;

mysql> update student set sex="女" where id=1;
Query OK, 0 rows affected (0.00 sec)

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

再回到事务A中读表数据,看是否改变

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

可以发现在mysql下避免了不可重复读。将之前修改的数据改回来

mysql> update student set sex="男" where id=1;
3. 可重复读

开启A事务,读取表中数据

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

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

打开另一个窗口,开启事务B,插入一条数据,并提交

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

mysql> insert into student values ("3","飞飞" ,"女" );
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
|  3 | 飞飞       | 女   |
+----+------------+------+
3 rows in set (0.00 sec)

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

在A事务中查看数据

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花轮          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

可以看出,A事务产生了幻读,因为实际上id=3这行数据是有的。

4. 串行化

前面的测试已经证明,在mysql的REPEATABLE-READ下,事务不会串行。

补充

这里多提一点,就是在REPEATABLE-READ下,事务是会发生死锁的,但mysql会自动给你处理死锁。

表student

学生id 学生姓名 学生性别
1 花轮
2 小丸子

表student1

学生id 学生姓名 学生性别
1 qq
2 ww
第一步,开启事务A,将student表 id=1 的 sex更改为女
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update student set sex="女" where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
第二步,开启事务B,将student1表 id=1 的 sex更改为男
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> 
mysql> update student1 set sex="男" where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
第三步,在事务A中,将student1表中 id=1的 sex更改为女
mysql> update student1 set sex="女" where id=1;

这里,事务A处于等待状态,因为这个更新操作需要等到事务B处理完成才能进行,而且如果超过一定时间没有处理,会提示超时错误

第四步,在事务B中,将将student1表中 id=1的 sex更改为男
mysql> update student set sex="男" where id=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

可以看到在事务B中报错,产生了死锁
再回去看事务A,发现第三步的更新成功了

mysql> update student1 set sex="女" where id=1;
Query OK, 0 rows affected (19.03 sec)
Rows matched: 1  Changed: 0  Warnings: 0

这里涉及到的其实是数据库锁的概念,以后有机会再写篇有关的文章


第一次写文章,有很多不足的地方,请多多见谅~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/48997.html

相关文章

  • MySQL学习笔记之InnoDB事务实现

    摘要:可串行化强制事务串行执行。当开始一个事务时,该事务的版本号肯定大于当前所有数据行快照的创建版本号,理解这一点很关键。多个事务必须读取到同一个数据行的快照,并且这个快照是距离现在最近的一个有效快照。将当前系统版本号作为数据行快照的删除版本号。 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式。同时数据库又是个高并发的应用,同一时间会有大量的并发...

    kyanag 评论0 收藏0
  • mysql 幻读的详解、实例及解决办法

    摘要:这其实并不是幻读,这是不可重复读的一种,只会在级别下出现,而在默认的隔离级别是不会出现的。 脏读/不可重复读的概念都比较容易理解和掌握,这里不在讨论 事务隔离级别(tx_isolation) mysql 有四级事务隔离级别 每个级别都有字符或数字编号 读未提交 READ-UNCOMMITTED | 0:存在脏读,不可重复读,幻读的问题 读已提交 READ-COMMITTED | 1:解...

    wizChen 评论0 收藏0
  • 重新理解mysql的锁、事务隔离级别及事务传播行为

    摘要:数据库多个事务之间操作可能出现的问题以及事务隔离级别是这篇文章介绍的重点。高级别的隔离可靠性较高,但系统开销较大。但该事务不要求与其他事务可串行化,可能会发生幻读。如果当前存在事务,则在嵌套事务内执行。 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。ACID,是指在可靠数据库管理系统(DBMS)中,...

    chadLi 评论0 收藏0
  • 关于MySQL的知识点与面试常见问题都在这里

    摘要:串行最高的隔离级别,完全服从的隔离级别。但是这将严重影响程序的性能。此外,垂直分区可以简化表的结构,易于维护。 我自己总结的Java学习的一些知识点以及面试问题,目前已经开源,会一直完善下去,欢迎建议和指导欢迎Star: https://github.com/Snailclimb/Java_Guide 书籍推荐 《高性能MySQL : 第3版》 文字教程推荐 MySQL 教程(菜鸟教程...

    hss01248 评论0 收藏0
  • 关于MySQL的知识点与面试常见问题都在这里

    摘要:串行最高的隔离级别,完全服从的隔离级别。但是这将严重影响程序的性能。此外,垂直分区可以简化表的结构,易于维护。 我自己总结的Java学习的一些知识点以及面试问题,目前已经开源,会一直完善下去,欢迎建议和指导欢迎Star: https://github.com/Snailclimb/Java_Guide 书籍推荐 《高性能MySQL : 第3版》 文字教程推荐 MySQL 教程(菜鸟教程...

    BothEyes1993 评论0 收藏0

发表评论

0条评论

rubyshen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<