MySQL 隔离级别
问题:隔离级别是为了解决并行执行的事务间因数据被修改而影响业务成败的问题。
“异常”的概念解释
脏读:A事务读取到B事务执行CRUD操作,但未提交的结果。
不可重复读:A事务执行同一SQL之间,B事务执行了CRUD操作且已提交,导致A事务前后两次读取到的数据不一致。
幻读:事务A根据某条件查询得到N条数据。随后事务B在该查询范围内插入了M条新数据并提交。当事务A第二次执行此查询时,发现结果集中有N+M条数据
隔离级别(从低到高)
⚠️ 隔离级别 对 当前会话 有效
- 读未提交
read-uncommitted
:A事务可读取B事务执行了CRUD操作但未提交的结果,导致脏读。 - 读已提交
read-committed
:A事务可读取B事务执行了CRUD提交了的结果,解决脏读,但没解决不可重复读——即A事务两次执行同一SQL,在读取数据的时间间隔中B事务执行了update/delete操作且提交,导致A事务前后两次读取到的结果不一致。 - 可重复读
repeatable-read
:A事务两次执行同一SQL,在读取数据的时间间隔中B事务执行了CRUD操作且提交,A事务前后两次读取到的结果一致;以第一次读取到的结果为准,即B事务未执行时数据的状态,解决不可重复读和脏读,未解决幻读(MySQL默认级别) - 串行化
serializable
:当一个事务正在执行CURD操作时,会阻塞其他事务的CRUD操作,不影响读操作。例:A事务新增10条数据且未提交,然后B事务执行CRUD,B事务将被阻塞,待A事务结束后再执行。解决脏读,不可重复读,幻读。
性能比较
隔离级别 | 解决问题 | 性能 |
---|---|---|
读未提交 | 🚫 | ⭐️⭐️⭐️⭐️ |
读已提交 | 脏读 | ⭐️⭐️⭐️ |
可重复读 | 脏读,不可重复读 | ⭐️⭐️ |
串行化 | 脏读,不可重复读、幻读 | ⭐️ |
⚠️ tips
就我个人用MySQL开发时的现象来看,MySQL的可重复读级别就已经解决了幻读现象,查资料知:因为MySQL的InnoDB存储引擎在可重复读隔离级别下使用了多版本并发控制(MVCC)和Next-Key Lock防止幻读。但MyISAM不支持MVCC或Next-Key Lock,因此在可重复读隔离级别下无法防止幻读。MyISAM等存储引擎通常不是事务型存储引擎,它们的隔离级别和事务处理能力与InnoDB存在显著差异。
隔离级别并不是用得越高越好——用的越高效率越慢,用默认的可重复读即可满足绝大块的开发需求。
修改隔离级别
# MYSQL v5.x版本用以下命令
select @@tx_isolation; # 查看当前会话的隔离级别
set tx_isolation='read-uncommitted'; # 读未提交
set tx_isolation='read-committed'; # 读已提交
set tx_isolation='repeatable-read'; # 可重复读
set tx_isolation='serializable'; # 串行化
# MySQL v8.x用以下命令
select @@transaction_isolation;
set transaction_isolation='read-uncommitted'; # 读未提交
set transaction_isolation='read-committed'; # 读已提交
set transaction_isolation='repeatable-read'; # 可重复读
set transaction_isolation='serializable'; # 串行化
🌄