Mysql事务的并发问题
【Mysql事务】在并发情况下会存在一系列的问题:脏读、不可重复读、幻读。
脏读:事务A读取了事务B未提交前修改的数据,但是事务B进行了回滚操作,导致事务A读取到了脏数据;
不可重复读:事务A多次读取数据a,读取过程中事务B对数据a进行了修改(a→b),导致事务A读取数据的结果出现不一致;
幻读:事务A进行多次范围查询,查询期间,事务B进行了数据的插入或者删除,导致事务A多次查询的结果记录数不一致。
【InnoDB中的锁】事务更新数据时加上独占锁,其他事务不可获得共享锁和独占锁,可以解决脏读问题;事务读取数据时加上共享锁,其他事务可以获取共享锁,不可获得独占锁,可以解决不可重复读问题;【InnoDB的行锁(Record Locks、Gap Locks、Next-Key Locks)】可以解决幻读问题。
Mysql事务的隔离级别
未提交读(read uncommitted):其他事务未提交的操作,在事务A可以看到;反之(事务A修改未提交,其他事务中也可以看到)也成立;
提交读(read committed):其他事务对数据进行修改的提交,事务A可以看到;
可重复读(repeatable read):事务A多次读取同一块数据(可能有其他事务对数据进行了修改)的结果是一致的;
串行化(serializable):事务串行执行。
Mysql事务的隔离级别 | 脏读 | 不可重复读 | 幻读 |
未提交读(read uncommitted) | 可能存在 | 可能存在 | 可能存在 |
提交读(read committed) | 不可能存在 | 可能存在 | 可能存在 |
可重复读(repeatable read) | 不可能存在 | 不可能存在 | 可能存在 |
串行化(serializable) | 不可能存在 | 不可能存在 | 不可能存在 |
以上可以参考【SQL92 ANSI/ISO标准】
注意:在mysql使用InnoDB引擎时,可重复读不会产生幻读问题(MVCC多版本并发控制)。
Mysql隔离级别的相关命令
select @@tx_isolation; -- 查看当前会话的隔离级别
select @@global.tx_isolation; -- 查看当前系统的隔离级别
set session transaction isolation level 隔离级别; -- 设置当前会话隔离级别
set global transaction isolation level 隔离级别; -- 设置系统当前隔离级别
Mysql的默认隔离级别为可重复读(repeatable-read)
修改会话隔离级别,只影响当前会话的隔离级别
修改系统隔离级别,不会影响已打开会话的隔离级别
将系统隔离级别修改成默认的可重复读(repeatable-read)
mysql隔离级别举例
以经典例子转账为例。在user表中增加一列money,表示用户拥有的金额,这里只做演示,直接使用int的数据类型,设置初始金额均为1000。
1、未提交读(read-uncommitted)
将窗口2的隔离级别也设置成未提交读,窗口1已经是未提交读,不需要再次设置
1)、出现脏读问题
2)、出现不可重复读问题
3)、出现幻读问题
2、提交读(read-commited)
将窗口1和窗口2设置成提交读
1)、不会出现脏读问题,出现不可重复读问题
2)、出现幻读问题
3、可重复读(repeatable read)
查看下引擎
将窗口1和窗口2设置成可重复读
1)、不会出现脏读问题,不会出现不可重复读的问题
2)、不会出现幻读问题
4、串行化(serializable)
将窗口1和窗口2的隔离级别设置为串行化
不存在脏读、不可重复读、幻读等问题(修改数据直接报错:等待获取锁超时),串行化会直接锁表。
如果有写的不对的地方,请大家多多批评指正,非常感谢!