关于 MySQL 重复读导致的重复插入问题

本文涉及的产品
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 本文介绍了在开发业务接口时遇到的MySQL重复读导致的数据重复插入问题,并通过伪代码示例详细解析了问题产生的原因。文章提出了四种解决方案:使用共享锁、控制事务并发执行、强制当前读以及调整隔离级别为READ COMMITTED,旨在确保读取最新数据,避免数据重复插入。

背景

昨天在写一个业务接口,遇到 MySQL 重复读导致的重复插入问题,下面是一段伪代码:

js

代码解读

复制代码

async function createClassOrder(uids, classId){
    // 事务开始
    await Promise.all(uids.map(uid => {
        // 将 TBL_CLASS 表进行行锁
        await db.execute('SELECT * FROM TBL_CLASS WHERE id=? FOR UPDATE', [classId])
        // 查找该用户是否已经预约过
        const classOrders = await db.execute('SELECT * FROM TBL_CLASS_ORDER WHERE classId=? AND uid=?', [classId, uid])
        // 如果已经预约过则进行报错
        if(classOrders.length > 0) {
            throw new Error('您已经预约')
        }
        // 创建预约,涉及到表 TBL_CLASS_ORDER
        // 更新课程信息,涉及到表 TBL_CLASS 
    }))
    // 事务结束
}
// 接口路由层有限制重复调用问题

可以发现,这段代码其实在最开始已经有数据库锁了,所以如果涉及到对表 TBL_CLASS 相同行数据进行操作时,事务 A 会进行锁定,事务 B 在执行相同行的时候,会进行等待,直到事务 A 结束,事务 B 再继续执行。但为什么仍然导致数据重复插入呢?原因就在 classOrders 里,当事务 A 结束后,事务 B 继续执行时,因为 MySQL 默认隔离级别是重复读,导致事务 B 在读取 classOrders 时仍然为空。

方案

找到原因,方案就比较容易了,目的就是读取最新数据,无论事务是否提交。

1. 使用共享锁

读取 TBL_CLASS_ORDER 行数据时读取最新数据,可以使用共享锁,例如

js

代码解读

复制代码

const classOrders = await db.execute('SELECT * FROM TBL_CLASS_ORDER WHERE classId=? AND uid=? LOCK IN SHARE MODE', [classId, uid])

2. 事务并发执行

事务 A 结束后再创建事务 B,可以在控制层进行限制。

3. 强制进行当前读

js

代码解读

复制代码

const classOrders = await db.execute('SELECT * FROM TBL_CLASS_ORDER WHERE classId=? AND uid=? FOR UPDATE', [classId, uid])

但可能会导致增加锁竞争

4. 设置隔离级别

设置 READ COMMITTED(读已提交)隔离级别

可以根据业务具体情况进行方案选择。


转载来源:https://juejin.cn/post/7423294364308734004

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
4月前
|
存储 人工智能 自然语言处理
游戏云,市场份额第一!
IDC最新报告显示,阿里云稳居中国游戏云市场第一,整体份额达41%。依托AI与云计算融合创新,助力米哈游、网易等企业出海,推动游戏研发、运营升级,持续引领行业发展。
527 0
游戏云,市场份额第一!
|
8月前
|
XML Linux 区块链
Python提取Word表格数据教程(含.doc/.docx)
本文介绍了使用LibreOffice和python-docx库处理DOC文档表格的方法。首先需安装LibreOffice进行DOC到DOCX的格式转换,然后通过python-docx读取和修改表格数据。文中提供了详细的代码示例,包括格式转换函数、表格读取函数以及修改保存功能。该方法适用于Windows和Linux系统,解决了老旧DOC格式文档的处理难题,为需要处理历史文档的用户提供了实用解决方案。
957 0
|
网络协议 Linux
CentOS7 yum安装报错“Could not resolve host: mirrorlist.centos.org;"之解决办法(换源)
CentOS7 yum安装报错“Could not resolve host: mirrorlist.centos.org; Name or service not known“之解决办法(换源)
ELK 圣经:Elasticsearch、Logstash、Kibana 从入门到精通
ELK是一套强大的日志管理和分析工具,广泛应用于日志监控、故障排查、业务分析等场景。本文档将详细介绍ELK的各个组件及其配置方法,帮助读者从零开始掌握ELK的使用。
|
Web App开发 应用服务中间件 网络安全
HTTPS证书到期更换
HTTPS证书到期更换
3748 0
|
JavaScript Java Maven
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
7481 1
|
弹性计算 Ubuntu Linux
阿里云服务器公共镜像、社区镜像、自定义镜像、共享镜像、云市场镜像区别及选择参考
阿里云服务器镜像有公共镜像、自定义镜像、共享镜像、镜像市场、社区镜像可选,对于新手用户来说,不知道他们之间的区别,因此往往不知道如何选择,本文为大家介绍他们之间的区别以及选择参考。
2421 12
|
关系型数据库 数据库 数据安全/隐私保护
springboot+dynamic-datasource多数据源配置动态切换
springboot+dynamic-datasource多数据源配置动态切换
5625 0
|
人工智能
写歌词的技巧和方法基础教程:引领你走进音乐世界,妙笔生词智能写歌词软件
音乐是灵魂的语言,歌词则是承载灵魂的载体。本文介绍写歌词的基础技巧,包括寻找灵感、确定主题、构建结构和运用语言,同时推荐《妙笔生词智能写歌词软件》作为创作助手,助力你走进丰富多彩的音乐世界。
|
索引
【UVM源码学习】uvm_packer
【UVM源码学习】uvm_packer
1549 0

热门文章

最新文章