沙滩星空的博客沙滩星空的博客

数据库事务的隔离级别与高并发下的脏数据问题

案例

A用户的余额为 1000 元。现在,B给A转账新增 100 元,同时,A给C转账扣除 50 元。
一波操作下来,正常A用户最终余额应为 1000+100-50=1050 元。而实际有可能变为 1000-50=950 元。

这就是典型的高并发条件下出现的脏数据问题。因为数据操作可能出现丢失更新

解决方案:

乐观锁 方案: 在提交阶段,先判断下原数据是否修改过。(读取数据时,同时获取版本号。数据有更新时,版本号加1。提交数据更新前,读取版本号,判断是否与之前一致,是则执行更新,并更新该数据的版本号。)

异步队列 方案:高并发的数据处理操作,全部堆栈到数据操作任务队列中,异步执行。如:电商秒杀使用的Redis异步队列

并发下事务会产生的问题

  1. 脏读: 事务A读到了事务B还没有提交的数据
  2. 不可重复读: 在一个事务里面读取了两次某个数据,读出来的数据不一致。
  3. 幻读: 在一个事务里面的操作中发现了未被操作的数据
  4. 丢失更新:两个不同的事务在某一时刻对同一数据进行读取后,先后进行修改。导致第一次操作数据丢失。

丢失更新产生的原因(两种)

第一类丢失更新(回滚丢失,Lost update) (通过设置隔离级别可以防止 Repeatable Read)。
A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题。
SQL92没有定义这种现象,标准定义的所有隔离界别都不允许第一类丢失更新发生

第二类丢失更新(覆盖丢失/两次更新问题,Second lost update) A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。
(实际上和不可重复读是同一种问题)

事务隔离级别

事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大。

1. Read UnCommitted(读未提交)

最低的隔离级别。一个事务可以读取另一个事务并未提交的更新结果。

2. Read Committed(读提交)

大部分数据库采用的默认隔离级别。一个事务的更新操作结果只有在该事务提交之后,另一个事务才可以的读取到同一笔数据更新后的结果。

3. Repeatable Read(重复读)

mysql的默认级别。整个事务过程中,对同一笔数据的读取结果是相同的,不管其他事务是否在对共享数据进行更新,也不管更新提交与否。

4. Serializable(序列化)

最高隔离级别。所有事务操作依次顺序执行。注意这会导致并发度下降,性能最差。通常会用其他并发级别加上相应的并发锁机制来取代它。

隔离级别脏读不可重复读幻读加锁读
READ_UNCOMMITTED
READ_COMMITED
REPEATABLE_READ
SERLALIZABLE

事物隔离级别查看及修改(MySQL)

查看默认事务隔离级别, 修改当前会话事务隔离级别, 修改全局事务隔离级别

select @@tx_isolation;
SET session TRANSACTION ISOLATION LEVEL Serializable;
SET global TRANSACTION ISOLATION LEVEL Serializable;

参数可以为:Read uncommitted|Read committed|Repeatable read|Serializable

总结

大多数数据库的默认的事务隔离级别是提交读(Read committed),而MySQL的事务隔离级别是重复读(Repeatable read)。对于丢失更新,只有在序列化(Serializable)级别才可得到彻底解决。不过对于高性能系统而言,使用序列化级别的事务隔离,可能引起死锁或者性能的急剧下降。
就具体开发过程而言,一般分为 悲观锁乐观锁 两种方式来解决并发冲突问题。

乐观锁(Optimistic Lock), 很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

悲观锁(Pessimistic Lock), 很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。


并发事务导致的丢失更新及处理方式详解 https://blog.csdn.net/qq_39445473/article/details/90488673
事务及事务隔离级别 https://www.cnblogs.com/xrq730/p/5087378.html
并发数据库事务缺锁导致的数据不一致情况:丢失更新,脏读,不可重复读,幻读 https://www.cnblogs.com/yfdream/p/7842917.html

php并发mysql数据库丢失更新处理 https://blog.csdn.net/weixin_30838971/article/details/113473666
未经允许不得转载:沙滩星空的博客 » 数据库事务的隔离级别与高并发下的脏数据问题

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址