MySQL事务隔离级别及脏读/幻读/不可重复读
首先解释几种异常的查询结果【关于异常场景的叫法不必太纠结,明白这几种异常记录状态,场景及解决办法即可】:
脏读
查询到其他事务未提交的数据.
不可重复读
同一事务中,完全相同的查询同一条结果集,执行两次查询结果不一致。因为别的事务可能更新了被查询的结果集。
幻读
同一事务中,完全相同的查询语句,两次执行后得到的结果集数目不一致。因为别的事务可能会更新记录,添加记录,删除记录,从而导致查询结果集数目变化。
为了解决这些问题,innodb引擎提供了四种隔离级别。这些隔离级别界定了一个事务所做的哪些修改可悲同时执行的事务看到。
隔离级别
READ UNCOMMITED
读未提交,可读取其他事务未提交的数据。
READ COMMITED
读已提交, 会读取其他事务已提交的数据。
REPEATABLE READ
可重复读,事务开启时生成快照,读取时都是基于快照读,也可使用for update 执行当前读,当前读会使用间隙锁和行锁影响其他事务的数据更新。
SERIALIZABLE
串行化 隔离级别最高,并发度最低。读取记录时,会加共享锁,事务提交时才释放。因此不会出现脏读幻读和不可重复读。
隔离性 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | 是 | 是 | 是 |
读已提交 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 否 |
串行化 | 否 | 否 | 否 |
查询全局和会话事务隔离级别:
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;
修改隔离级别
MySQL 提供了 SET TRANSACTION 语句,该语句可以改变单个会话或全局的事务隔离级别。语法格式如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
SESSION:
表示修改的事务隔离级别将应用于当前 session(当前 cmd 窗口)内的所有事务;
GLOBAL:
表示修改的事务隔离级别将应用于所有 session(全局)中的所有事务,且当前已经存在的 session 不受影响;
省略 SESSION 和 GLOBAL
表示修改的事务隔离级别将应用于当前 session 内的下一个还未开始的事务。
任何用户都能改变会话的事务隔离级别,但是只有拥有 SUPER 权限的用户才能改变全局的事务隔离级别。