mysql事务隔离级别

来源:这里教程网 时间:2026-03-01 11:43:01 作者:

本文主要讨论 mysql 中的事务隔离级别。  

总述

Innodb 存储引擎实现了四中事务隔离级别。  

(一)   读未提交( READ UNCOMMITTED ),简称 RU ,一个事务可以读到另一个事务的未提交更新,也就是脏读的现象。

(二)   读已提交( READ COMMITTED , 简称 RC ,也叫不可重复读, Oracle 的默认隔离级别。一个事务中可以读到其他事务的提交 dml 动作。该隔离级别解决了脏读的问题,但是针对提交的 insert 语句等,会出现幻读的现象。

(三)   可重复读( REPEATABLE-READ )是 mysql 默认的事务隔离级别,简称 RR 。该级别解决了之前存在的幻读,脏读现象。

(四)   串行( SERIALIZABLE ),对读取的数据行加表级共享锁,更新数据时加表级排他锁,基本没什么并发能力了。    

RU 实验

mysql5.7.22 默认级别 mysql> show variables like '%iso%'; +-----------------------+-----------------+ | Variable_name         | Value           | +-----------------------+-----------------+ | transaction_isolation | REPEATABLE-READ   | | tx_isolation          | REPEATABLE-READ | +-----------------------+-----------------+ 2 rows in set (0.00 sec)   两个会话在会话级别设置成读未提交级别。   会话级别修改 mysql> set session   tx_isolation='READ-UNCOMMITTED'; Query OK, 0 rows affected, 1 warning   (0.00 sec)   mysql> show variables like   '%iso%';                +-----------------------+------------------+ | Variable_name         | Value            | +-----------------------+------------------+ | transaction_isolation |   READ-UNCOMMITTED | | tx_isolation          | READ-UNCOMMITTED | +-----------------------+------------------+ 2 rows in set (0.00 sec)   会话 a mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 255.255.255.255 | +-----------------+ 2 rows in set (0.00 sec)   会话 b 插入一条数据 mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> insert into test1 values(2); Query OK, 1 row affected (0.00 sec)     返回会话 a mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | +-----------------+ 3 rows in set (0.00 sec)  

     

RC 实验

设置会话级别隔离级别 mysql> set session   tx_isolation='READ-COMMITTED'; Query OK, 0 rows affected, 1 warning   (0.00 sec)   mysql> show variables like '%iso%';              +-----------------------+----------------+ | Variable_name         | Value          | +-----------------------+----------------+ | transaction_isolation | READ-COMMITTED   | | tx_isolation          | READ-COMMITTED | +-----------------------+----------------+   会话 a mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | +-----------------+ 3 rows in set (0.00 sec)   会话 b 插入一条数据,未提交 mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> insert into test1 values(3); Query OK, 1 row affected (0.01 sec)   此时会话 a 看不到 mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | +-----------------+ 3 rows in set (0.00 sec)     会话 b 提交 mysql> commit; Query OK, 0 rows affected (0.00 sec)   返回会话 a mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | | 3               | +-----------------+ 4 rows in set (0.00 sec) 这种现象就是幻影读了。  

       

RR 实验

mysql> show variables like '%tx%'; +---------------+-----------------+ | Variable_name | Value           | +---------------+-----------------+ | tx_isolation  | REPEATABLE-READ | | tx_read_only  | OFF             | +---------------+-----------------+ 2 rows in set (0.00 sec)   会话 a mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | | 3               | | 4               | | 5               | +-----------------+ 6 rows in set (0.00 sec)   会话 b 插入一条数据,未提交 mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> insert into test1 values(6); Query OK, 1 row affected (0.00 sec)   会话 a 没有看到会话 b 新插入的数据 mysql> select * from test1; +-----------------+ | a                 | +-----------------+ | 1               | | 2               | | 255.255.255.255 | | 3               | | 4               | | 5               | +-----------------+ 6 rows in set (0.00 sec)   会话 b 提交 mysql> commit;   会话 a 还是没有看到 mysql> select * from test1; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | | 3               | | 4               | | 5               | +-----------------+ 6 rows in set (0.00 sec)   想要看到的话需要加 for   update mysql> select * from test1 for update; +-----------------+ | a               | +-----------------+ | 1               | | 2               | | 255.255.255.255 | | 3               | | 4               | | 5               | | 6               | +-----------------+ 7 rows in set (0.00 sec)  

 

串行实验

串行( SERIALIZABLE ),对读取的数据行加表级共享锁,更新数据时加表级排他锁,基本没什么并发能力了。   设置会话级别事务隔离级别 mysql> set session   tx_isolation='serializable'; Query OK, 0 rows affected, 1 warning   (0.00 sec)     会话 a 删除一行数据 mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> delete from test1 where a='6'; Query OK, 1 row affected (0.00 sec)   会话 bselect 语句都会夯住 mysql> begin; Query OK, 0 rows affected (0.00 sec)   mysql> select * from test1;       会话 c 查看锁的状态  INFORMATION_SCHEMA.INNODB_LOCKS; +-------------------------+-----------------+-----------+-----------+------------------+ | lock_id                 | lock_trx_id     | lock_mode | lock_type | lock_table       | +-------------------------+-----------------+-----------+-----------+------------------+ | 421706548341472:158:4:8 | 421706548341472 | S          | RECORD    | `mingdb`.`test1` | | 14604:158:4:8           | 14604           | X          | RECORD    | `mingdb`.`test1` | +-------------------------+-----------------+-----------+-----------+------------------+   过了一段时间后,会话 b 返回 ERROR 1205 (HY000): Lock wait timeout   exceeded; try restarting transaction 这个时间是由 innodb_lock_wait_timeout 决定的 mysql> show variables like   'innodb_lock_wait_timeout'; +--------------------------+-------+ | Variable_name            | Value | +--------------------------+-------+ | innodb_lock_wait_timeout | 50    | +--------------------------+-------+ 1 row in set (0.01 sec)  

         

相关推荐