Skip to main content

Mysql并发访问事务问题

· 8 min read
Zeffon Wu

Mysql 事务并发访问导致的问题--更新丢失、脏读、不可重复读、幻读。 Mysql 数据库事务的四大特性--原子性、一致性、隔离性、持久性。而是数据库中的一个非常重要的概念,它主要用于多用户环境下保证数据库完整性一致性。如果在多用户并发情况下,他们的事务同时相同的数据进行操作,是会导致更新丢失、脏读、不可重复读、幻读的问题的。

前言

Mysql 事务并发访问导致的问题--更新丢失、脏读、不可重复读、幻读。 Mysql 数据库事务的四大特性--原子性、一致性、隔离性、持久性。而是数据库中的一个非常重要的概念,它主要用于多用户环境下保证数据库完整性一致性。如果在多用户并发情况下,他们的事务同时相同的数据进行操作,是会导致更新丢失、脏读、不可重复读、幻读的问题的。

更新丢失

  1. Mysql 所有事务隔离级别在数据库层面上均可避免更新丢失问题
  2. 当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。
  3. 每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。
  4. 如果在A事务完成之后,B事务才能进行更改,则可以避免该问题。

更新丢失 Demo

取款事务存款事务
开始事务开始事务
查询转账余额为 100 元
查询转账余额为 100 元
存入 20 元,余额变为 120 元
提交事务
取出 10 元,余额改为 90 元
回滚事务,余额恢复为 100 元更新丢失

脏读

  1. READ-COMMITTED 事务隔离级别以上可避免--脏读问题
  2. 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
  3. 如果在B事务确定最终更改前,A事务或者其它事务都不能读取更改的文档,则可以避免该问题。

脏读 Demo

数据库默认的隔离级别是 REPEATABLE-READ。为了演示脏读效果,需要先将数据库隔离级别设置成 READ-UNCOMMITTED。

select @@tx_isolation;
set session transaction isolation level read uncommitted;
A 事务B 事务
开始事务开始事务
1 账户余额 1000 元,转出 100 元
查询 1 账户剩 900 元
查询 1 账户剩 900 元
没有进行事务提交,而是事务回滚,余额恢复 1000 元
不知道 A 事务进行回滚,对 1 账户存入 200 元
提交事务
再次查询 1 账户余额 1100

不可重复读

  1. REPEATABLE_READ 事务隔离级别以上可避免--不可重复读问题
  2. 不可重复读是指在一个事务内,多次同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。
  3. 如果在B事务确定最终更改前A事务或者其它事务都不能读取更改的文档,则可以避免该问题。

不可重复读 Demo

A 事务B 事务
开始事务开始事务
查询 1 账户余额 1300 元
对 1 账户存入 300 元
查询 1 账户剩 1600 元
进行事务提交
查询 1 账户余额 1600 元
  • 数据库默认的隔离级别是 REPEATABLE-READ。若将数据库隔离级别设置成 REPEATABLE_READ,则A事务第二次查询余额还是 1300 元,不会是 1600 元。
select @@tx_isolation;
set session transaction isolation level repeatable read;

幻读

  1. SERIALIZABLE 事务隔离级别可避免--幻读问题
  2. 幻读与不可重复读看似类似,不可重复读侧重于对同一数据的修改,幻读侧重于新增删除
  3. 幻觉读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

幻读 Demo

A 事务B 事务
开始事务开始事务
查询全部账号余额,当前有 3 个账号
新增 4 账号及其余额
进行事务提交
更新所有的账户余额
出现有四个账号幻读的现象
  • 数据库默认的隔离级别是 REPEATABLE-READ。若将数据库隔离级别设置成 SERIALIZABLE,则B事务新增账号 4 需要等待A事务操作完才能进行。
select @@tx_isolation;
set session transaction isolation level serializable;

总结

事务并发访问引起的问题以及如何避免

事务隔离级别更新丢失脏读不可重复读幻读
未提交读避免发生发生发生
已提交读避免避免发生发生
可重复读避免避免避免发生
串行化避免避免避免避免
  • 事务级别越高安全性越高,串行化执行越严重,这样就可以降低数据库的并发度,但性能要求也会越高。

文献参考

sql 语句对数据库表进行加锁和解锁