并发事务更新问题

简介: 并发事务更新问题

本文的所有内容基于 mysql InnoDB 和 sequelize。



问题



多个并发的事务对同一行数据进行更新,且更新的数据是基于这一行数据更新前的数据计算的结果,造成了此行数据更新的问题。



事务与锁简述



mysql 本身并不具有事务,事务是 InnoDB 引擎所有的功能,事务的隔离级别分为四种:


1、READ_UNCOMMITTED:脏读,一个事务能读到另一个事务未提交的数据,事务的隔离级别最低。


2、READ_COMMITTED:不可重复读,一个事务对一行数据进行更新的过程中,另一个事务对同一行数据进行读取,会在此行数据更新提交前后读取到不一致的结果。避免了脏读的情况,隔离级别比脏读略高一级。


3、REPEATABLE_READ:幻读,同一个事务内读取的数据是保证相同的,但当事务非独立执行时仍然会造成读取的结果不一致。默认的事务隔离级别,比不可重复读高一级。


4、SERIALIZABLE:序列化,事务的隔离级别最高,避免了上述的问题。


两种锁:


1、共享锁:读锁,获取共享锁的事务只能读,不能修改数据,多个事务可同时获取共享锁。


2、排他锁:写锁,一个事务获取写锁后可对数据进行读写,但其他事务无法再获取到写锁直到上一个事务完成。



sequelize 示例



解决方式:使用 SERIALIZABLE 事务隔离级别,但这并不够,我们仍然需要保证多个事务并发下读取的原始数据一定是之前事务提交更新之后的数据,因此还需要使用排他锁。


以下图片使用了 async/await 的写法,包含了事务的操作和 lock 锁的使用,仅供参考,sequelize 模型的定义可参考上一篇文章 -- 数据库时间类型数据的处理 ,不必深究具体的业务实现:



需要注意的是,使用排他锁时,如果查询操作不是根据主键或索引,那么会造成表锁,这会对数据库读写性能造成很大的影响,显然这并不是我想要的,我们更需要的是行锁,所以在使用排他锁时,应该使用主键或索引进行操作。



结语



除了在数据库层面上解决这个问题之外,还有另一种方法就是将这些操作同一行数据的并发事务改为串行执行。


另一个问题是 pm2 的集群模式下的并发事务会发生什么呢?

目录
相关文章
|
9月前
|
缓存 数据库
并发修改同一记录时需要加锁
并发修改同一记录时需要加锁
|
2月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
5月前
|
NoSQL 前端开发 Java
【幂等性大坑】事务提交前释放锁导致锁失效问题
在事务中,使用了 Redis 分布式锁.这个方法一旦执行,事务生效,接着就 Redis 分布式锁生效,代码执行完后,先释放 Redis 分布式锁,然后再提交事务数据,最后事务结束。如果是表单重复提交场景,可以尝试给“订单号”等有唯一性的字段加唯一索引,这样重复提交时会因为唯一索引约束导致索引失效。5、如果表的一个字段,要作为另外一个表的外键,这个字段必须有唯一约束(或是主键),如果只是有唯一索引,就会报错。2、创建唯一约束,会自动创建一个同名的唯一索引,该索引不能单独删除,删除约束会自动删除索引。
|
5月前
|
存储
6-4|原子性更新
6-4|原子性更新
|
数据库
【并发事务会产生哪些问题】
【并发事务会产生哪些问题】
160 0
|
9月前
|
数据库连接 数据库
多线程事务失效的原因
【5月更文挑战第16天】多线程事务失效的原因
460 0
|
9月前
|
SQL 关系型数据库 MySQL
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
215 1
|
9月前
|
关系型数据库 MySQL 数据库
事务和锁:保证数据一致性
事务和锁:保证数据一致性
97 0
|
SQL 关系型数据库 MySQL
两个事务并发写,能保证数据唯一吗?
两个事务并发写,能保证数据唯一吗?
158 0
|
数据库
并发事务带来哪些问题?
并发事务带来哪些问题?
165 0