Mysql的事务隔离级别


前言

什么是隔离性?

与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性,是指不同事务的内部操作是隔离的,并发执行时各个事务之间不互相干扰。
严格的隔离性,对应了事务隔离级别中的Serializable(序列化),但实际应用中出于性能方面的考虑很少使用序列化。


一、事务隔离级别

SQL标准中定义了4种隔离级别:读未提交、读已提交、可重复读和序列化。一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差。
隔离级别与读取问题的关系如下:

隔离级别脏读不可重复读幻读
Read Uncommitted可能可能可能
Read Committed不可能可能可能
Repeatable Read不可能不可能可能
Serializable不可能不可能不可能

二、默认隔离级别

在大多数数据库系统中,默认使用的隔离级别是读已提交(如Oracle)或可重复读(如Mysql和InnoDB)。需要注意的是,在SQL标准中,可重复读不能避免幻读问题,但是InnoDB的可重复读避免了幻读的问题(它是怎么做到呢?)

三、使用演示

3.1 读未提交

1.事务1设置事务隔离级别为读未提交,开启事务后查询users表id=1的数据。

>mysql set session transaction isolation level read uncommitted;
>mysql start transaction;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

2.事务2开启事务,修改users表id=1的数据但未提交。

>mysql start transaction;
>mysql update users set cname='刘二' where id=1;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘二  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.事务1再次查询users表id=1的数据,看到未提交的数据即出现“脏读”问题。

>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘二  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.2 读已提交

1.事务1设置事务隔离级别为读已提交,开启事务后查询users表id=1的数据。

>mysql set session transaction isolation level read committed;
>mysql start transaction;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

2.事务2开启事务,修改users表id=1的数据但未提交。

>mysql start transaction;
>mysql update users set cname='刘二' where id=1;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘二  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.事务1再次查询users表id=1的数据,仍看到旧的数据即不再出现脏读。

>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.事务2提交后,事务1再次查询users表id=1的数据,看到已提交的数据即出现“不可重复读”问题。

>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘二  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.3 可重复读

1.事务1设置事务隔离级别为可重复读,开启事务后查询users表id=1的数据。

>mysql set session transaction isolation level repeatable read;
>mysql start transaction;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

2.事务2开启事务,修改users表id=1的数据且提交。

>mysql start transaction;
>mysql update users set cname='刘二' where id=1;
>mysql commit;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘二  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.事务1再次查询users表id=1的数据,看到旧的数据即出现“幻读”问题。
在可重复读设置下,数据库系统直接返回上次查询的结果。幻读:读取到的数据,与数据库真实的数据不一致(被其他修改了)

>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

3.4 序列化

1.事务1设置事务隔离级别为序列化,开启事务后查询users表id=1的数据。

>mysql set session transaction isolation level serializable;
>mysql start transaction;
>mysql select * from users where id=1;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  1 | 刘一  | 666      |
+----+-------+----------+
1 row in set (0.00 sec)

2.事务2开启事务,去修改users表id=1的数据,等待数秒后获取锁超时而修改失败。
–因为事务1对users表id=1的数据加了“行级锁”且未释放,则事务2不能对它修改。

>mysql start transaction;
>mysql update users set cname='刘二' where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

3.事务2去修改users表id=2的数据,修改成功。
–因为事务1只对users表id=1的数据加了“行级锁”而不是全表,所以id=2可以被其他事务修改。

>mysql update users set cname='王wu' where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

>mysql select * from users where id=2;
+----+-------+----------+
| id | cname | password |
+----+-------+----------+
|  2 | 王wu  | 111      |
+----+-------+----------+
1 row in set (0.00 sec)

总结

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。
尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用乐观锁悲观锁来控制。(什么是乐观锁和悲观锁,可以下一篇日志继续,哈哈~)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值