Skip to main content

Command Palette

Search for a command to run...

高并发下重复插入问题及更新同一行数据

Published
•1 min read•View as Markdown
E

Science is gold.

重复插入问题

很多业务场景下,我们需要记录有唯一性,不允许重复插入。一般业务代码的逻辑通常是先查询,表记录存在则返回,不存在则插入数据。

但是在高并发场景下,多个线程同时进行查询,都查询到没有记录,随后都进行插入,这样就会出现需要唯一记录的重复插入。

解决方案

方案一: 使用悲观锁/分布式锁

该方案实现简单,但很影响性能。

方案二: 唯一性约束

使用 唯一性约束 ,业务代码通过捕获唯一性约束冲突的异常进行处理。但如果表设计中存在状态字段,唯一约束是某种状态的约束,那么添加唯一性约束的方式就不可行了。

方案三: 更改 sql

insert into [Table] (a,b) select 'v1','v2' from [Table] 
where not exist (select id from [Table] where a = 'v1' and b = 'v2');

这种方式是比较简单的,业务代码可以通过返回值来做后续逻辑处理。

方案四: 做接口访问次数限制

这种方案是限制接口在短时间内被多次调用,如果业务上能确定接口不可能在很短时间内使用相同参数调用,完全可以做限制。

缺点是需要额外设计接口重复调用拦截处理。

方案五: insert on duplicate key update

mysql中支持这个语法:

insert into table1 (xx,xxx) values (xx,xxx) on duplicate key update

在添加数据时,mysql发现数据不存在,则直接insert。如果发现数据已经存在了,则做update操作。不过要求表中存在唯一索引或 PRIMARY KEY,这样当这两个值相同时,才会触发更新操作,否则是插入。

此外,insert on duplicate key update 在高并发的情况下,可能会产生死锁。

方案六: insert ignore

mysql中支持这个语法:

insert ignore into table1 (xx,xxx) values (xx,xxx)

在insert语句执行的过程中:mysql发现如果数据重复了,就忽略,否则就会插入。它主要是用来忽略,插入重复数据产生的 Duplicate entry 'XXX' for key 'XXXX'异常的。不过也要求表中存在唯一索引或 PRIMARY KEY。

另外,使用 insert ... ignore 也有可能会导致死锁。

方案七: 防重表

添加一张防重表,表中设置不可重复字段为唯一索引列。

业务中在添加数据前,先添加防重表。如果添加成功,说明可以正常添加商品;如果添加失败,说明有重复数据。

高并发下更新同一行数据

方案一: 使用悲观锁

悲观锁当前只有一个线程执行操作,排斥外部请求的修改。遇到加锁的状态,就必须等待。结束了唤醒其他线程进行处理。虽然可以解决数据安全问题,但在高并发下,很多请求都在锁等待,某些线程可能永远没机会抢到锁,性能极差。

方案二: FIFO缓存队列

直接将请求放入队列中,就不会导致某些请求永远获取不到锁。解决了锁的问题,全部请求采用“先进先出”的队列方式来处理。高并发的场景下,因为请求很多,很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态。或者设计一个极大的内存队列,也是一种方案,但队列内的请求可能会越来越多,系统响应时间还是会大幅下降。

方案三: 使用乐观锁

通过使用 “版本号(version)”机制。这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功。综合来说,这是一个比较好的解决方案。

More from this blog

C# 标准性能测试高级用法(Benchmark)

在 C# 标准性能测试 已经告诉大家如何使用 BenchmarkDotNet 测试性能,本文会告诉大家高级的用法。 建议是创建一个控制台项目用来做性能测试,这个项目要求是 dotnet framework 4.6 以上,建议是 dotnet 7 的版本。使用这个项目引用需要测试的项目,然后在里面写测试的代码。 例如被测试项目有一个类 Foo 里面有一个叫 Lindexidb 的方法,接下来的任务是需要测试这个 Lindexidb 方法的性能 最简单的测试的代码 public class FooP...

Jan 9, 20247 min read

.NetCore 实践——HttpClientFactory[一]

HttpClientFactory介绍 HttpClientFactory 主要有下面的功能: 管理内部HttpMessageHandler 的生命周期,灵活应对资源问题和DNS刷新问题 支持命名话、类型化配置,集中管理配置,避免冲突。 灵活的出站请求管道配置,轻松管理请求生命周期 内置管道最外层和最内层日志记录器,有information 和 Trace 输出 核心对象: HttpClient HttpMessageHandler SocketsHttpHandler De...

Jan 9, 20245 min read

认识 MSBuild - 1

前言 很多人一谈到 MSBuild,脑子里就会出现 “XML”、“只能用 VS 的属性框图形界面操作”、“可定制性和扩展性差” 和 “性能低” 等印象,但实际上这些除了 “XML” 之外完全都是刻板印象:这些人用着 Visual Studio 提供的图形界面,就完全不愿意花个几分钟时间翻翻文档去理解 MSBuild 及其构建过程。 另外,再加上 vcxproj (Visual C++ 项目)的默认 MSBuild 构建文件写得确实谈不上好(默认只能项目粒度并行编译,想要源码级并行编译你得加钱),...

Jan 9, 20245 min read

.NetCore实战——工作单元模式(UnitOfWork):管理好你的事务

工作单元模式有如下几个特性: 1、使用同一上下文 2、跟踪实体的状态 3、保障事务一致性 我们对实体的操作,最终的状态都是应该如实保存到我们的存储中,进行持久化 接下来看一下代码 为了实现工作单元模式,这里定义了一个工作单元的接口 public interface IUnitOfWork : IDisposable { Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); Task<b...

Jan 9, 20242 min read
E

Edward Chu's blog

41 posts