当前位置:Gxlcms > 数据库问题 > MySQL事务以及隔离级别

MySQL事务以及隔离级别

时间:2021-07-01 10:21:17 帮助过:5人阅读

脏读 不可重复读 幻读 读未提交(read-uncommitted) 是 是 是 不可重复读(read-committed) 否 是 是 可重复读(repeatable-read) 否 否 是 串行化(serializable) 否 否 否

四. 举例说明

  1. 读未提交

    (1) 打开一个客户端A, 并设置当前事务模式为read uncommitted(读未提交), 处查询表account的初始值: 

技术图片

    (2) 在客户端A的事务提交之前, 打开另一个客户端, 更新表account:

技术图片

    (3) 这时, 虽然客户端B的事务还没有提交, 但是客户端A就可以查询到B已经更新的数据:

技术图片

    (4) 一旦客户端B的事务因为某种原因回滚, 所有的额操作都将会插销, 那么客户端A查询到的数据其实就是脏数据:

技术图片

    (5) 在客户端执行更新语句 update account set balance = balance - 50 where id = 1, lilei的balance没有变成350, 而是400, 这样数据就会不一致. 因为在此客户端中并不知道在其他的客户端已经回滚了, 所以查询还是之前查到的数据, 想要解决这个问题可以采用读已提交的隔离级别

技术图片

  2. 读已提交

    (1) 打开一个客户端A, 并设置当前事务模式为read committed(读已提交), 查询表account的所有记录

技术图片

    (2) 在客户端A的事务提交之前, 打开另一个客户端B, 更新表account

技术图片

    (3) 这时, 客户端B的事务还没有提交, 客户端A不能查询到B已经更新的数据, 解决了脏读的问题

技术图片

    (4) 客户端B的事务提交

技术图片

    (5) 客户端A执行与上一步相同的查询, 结果与上一步不一致, 即产生了不可重复读的问题

技术图片

  3. 可重复读

    (1) 打开一个客户端A, 并设置当前事务模式为repeatable read, 查询表account的所有记录

技术图片

    (2) 在客户端A的事务提交之前, 打开另一个客户端B, 更新表account并提交

技术图片

    (3) 在客户端A查询表account的所有记录, 与步骤(1)的查询结果一致, 没有出现不可重复读的问题

技术图片

    (4) 在客户端A, 接着执行update balance = balance - 50 where id = 1, balance没有变成400-50=350, 李磊的balance值用的四步骤(2)中的350来计算的, 所以是300, 数据的一致性到是没有被破坏. 可重复读的隔离级别下使用了MVCC机制, select操作不会更新版本号, 是快照读(历史版本); insert, update和delete会更新版本号, 是当前读(当前版本)

技术图片

    (5) 重新打开客户端B, 插入一条新数据后提交

技术图片

    (6) 在客户端A查询表account的所有记录, 没有查出新增数据, 所以没有出现幻读

技术图片

  4. 串行化

    (1) 打开一个客户端A, 并设置当前事务模式为serializable, 查询表account的初始值

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

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

mysql> select * from account;
+------+--------+---------+
| id   | name   | balance |
+------+--------+---------+
|    1 | lilei  |   10000 |
|    2 | hanmei |   10000 |
|    3 | lucy   |   10000 |
|    4 | lily   |   10000 |
+------+--------+---------+
4 rows in set (0.00 sec)

    (2) 打开一个客户端B, 并设置当前事务模式为serializable, 插入一条记录报错, 表被锁了插入失败, mysql种食物隔离级别为serializable时会锁表, 因此不会出现幻读的情况, 这种隔离级别并发性极低, 开发中很少会用到

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

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

mysql> insert into account values(5,tom,0);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

总结 :

  1. 事务隔离性级别为读提交时, 写数据只会锁住相应的行

  2. 事务隔离级别为可重复读时, 如果检索条件有索引(包括主键索引)的时候, 默认加锁方式是next-key锁; 如果检索条件没有索引, 更新数据时会锁住整张表. 一个间隙被事务加了锁, 其他事务是不能在这个间隙插入记录的, 这样可以防止幻读

  3. 事务隔离级别为串行时, 读写数据都会锁住整张表

  4. 隔离级别越高, 云哥不敢保证数据的完整性和一致性, 但是对并发性能的影响也越来越大.

MySQL事务以及隔离级别

标签:不同的   lan   let   保存   加锁   ESS   innodb   read   size   

人气教程排行