【MySQL】事务隔离级别

今天利用空闲时间给大家分享一下个人对事务隔离级别的理解,我们生活中应该都有存钱取钱的经历吧,那么我就用存钱取钱这个例子来讲解。
现在银行有一张money表,大概记录了交易id,客户名称,客户余额。

  • READ-UNCOMMITTED
    (1)所有事务都可以看到其他未提交事务的执行结果
    (2)本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少
    (3)该级别引发的问题是——脏读(Dirty Read):读取到了未提交的数据

小明在在ATM机往自己账户存入100元,此时未点确定,但是小明老婆小红却看到小明账户已经有100元了。
小明:

06:48:10 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

06:48:24 [email protected] [xucl]>insert into money values(1,'小明',100);
Query OK, 1 row affected (0.00 sec)

小红:

06:48:38 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    100 |
+------+--------+--------+
1 row in set (0.00 sec)
  • READ-COMMITED
    (1)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)
    (2)它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变
    (3)这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。
    |——>导致这种情况的原因可能有:
    (1)有一个交叉的事务有新的commit,导致了数据的改变;
    (2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit
    我们还是用例子来理解这件事情,小红打算去取小明卡里的钱的时候,看到了小明卡里有100元,这个时候小明往自己卡里又偷偷存了100元进去,小红取消了取钱,上面显示小明卡里有200块了。
    小红:
06:55:56 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

06:56:02 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    100 |
+------+--------+--------+
1 row in set (0.00 sec)

此时小明偷偷存入100元并提交:

06:56:30 [email protected] [xucl]>update money set cmoney=200 where tid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

06:58:24 [email protected] [xucl]>commit;
Query OK, 0 rows affected (0.00 sec)

此时小红取消交易,再次查看余额显示200元

06:56:04 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    200 |
+------+--------+--------+
1 row in set (0.00 sec)

如果把小红取钱看成一次交易的话,在交易的过程中看到的两次余额不一样,这就是不可重复读。

  • REPEATABLE READ
    (1)这是MySQL的默认事务隔离级别
    (2)它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行
    (3)此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
    (4)InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题
    下面我们来看例子:
    小红:
07:12:40 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

07:12:51 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    200 |
+------+--------+--------+
1 row in set (0.00 sec)

小明:

07:12:31 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

07:13:08 [email protected] [xucl]>update money set cmoney=300 where tid=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

07:13:26 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    300 |
+------+--------+--------+
1 row in set (0.00 sec)

07:13:34 [email protected] [xucl]>commit;
Query OK, 0 rows affected (0.00 sec)

小红再次查看:

07:12:57 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    200 |
+------+--------+--------+
1 row in set (0.00 sec)

显示还是只有200元,小红取出卡后再次查看就变成300元了。

07:16:57 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

07:17:00 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    300 |
+------+--------+--------+
1 row in set (0.00 sec)
  • SERIALIZABLE
    (1)这是最高的隔离级别
    (2)它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。
    (3)在这个级别,可能导致大量的超时现象和锁竞争
    简单来说就是小红一旦查看小明的账户,这个时候小明想要偷偷存钱进去就没办法了。
    小红:
07:24:52 [email protected] [xucl]>start transaction;
Query OK, 0 rows affected (0.00 sec)

07:25:33 [email protected] [xucl]>select * from money;
+------+--------+--------+
| tid  | cname  | cmoney |
+------+--------+--------+
|    1 | 小明   |    300 |
+------+--------+--------+
1 row in set (10.04 sec)

小明:

07:26:15 [email protected] [xucl]>update money set cmoney=400 where tid=1;
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

小明发现自己的钱存不进去了。
简单总结
一、

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

二、事务隔离等级高->低:
serializable -> repeatable-read -> read-committed -> read-uncommitted

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

你可能感兴趣的:(【MySQL】事务隔离级别)