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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文介绍了在开发业务接口时遇到的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 
相关文章
|
NoSQL 数据可视化 关系型数据库
推荐几个好用的redis可视化工具
推荐几个好用的redis可视化工具
17463 1
|
12月前
|
数据库
三大范式的特点
第一范式确保数据库表中每列都是不可分割的基本数据项,无重复列;第二范式在满足第一范式基础上,要求每个实例被唯一标识,属性完全依赖于主键;第三范式在满足第二范式基础上,排除非主键信息的冗余,避免数据重复。
337 0
|
机器学习/深度学习 算法 搜索推荐
深度学习之差分隐私
基于深度学习的差分隐私是一种在保护用户隐私的同时使用数据进行模型训练的技术。它的核心理念是通过加入随机噪声来隐藏个体数据的影响,防止在分析或模型训练过程中泄露个人信息。
1251 1
|
10月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
4911 13
Spring Boot 3 集成 Spring Security + JWT
|
小程序 开发者
万能的微信小程序个人主页:商城系统个人主页、外卖系统个人主页、购票系统个人主页等等【全部源代码分享+页面效果展示+直接复制粘贴编译即可】
这篇文章分享了四个不同应用场景下的微信小程序个人主页的源代码和页面效果展示,包括商城系统、外卖系统、医疗挂号和电影购票系统的个人主页。提供了完整的页面布局和样式代码,允许开发者直接复制粘贴并根据自己的项目需求进行简单的改造使用。
万能的微信小程序个人主页:商城系统个人主页、外卖系统个人主页、购票系统个人主页等等【全部源代码分享+页面效果展示+直接复制粘贴编译即可】
|
监控 数据可视化 数据挖掘
ERP系统中的数据分析与决策支持解析
【7月更文挑战第25天】 ERP系统中的数据分析与决策支持解析
1080 0
|
12月前
|
存储 JSON Java
ELK 圣经:Elasticsearch、Logstash、Kibana 从入门到精通
ELK是一套强大的日志管理和分析工具,广泛应用于日志监控、故障排查、业务分析等场景。本文档将详细介绍ELK的各个组件及其配置方法,帮助读者从零开始掌握ELK的使用。
|
网络协议 Linux
CentOS7 yum安装报错“Could not resolve host: mirrorlist.centos.org;"之解决办法(换源)
CentOS7 yum安装报错“Could not resolve host: mirrorlist.centos.org; Name or service not known“之解决办法(换源)
|
JavaScript Java Maven
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
理解固化的Maven依赖:spring-boot-starter-parent 与 spring-boot-dependencies
6486 1
|
设计模式 缓存 Devops
微服务架构最强讲解,那叫一个通俗易懂!
微服务架构(Microservice Architecture)是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。你可以将其看作是在架构层次而非获取服务的
32087 3
微服务架构最强讲解,那叫一个通俗易懂!