业务需求:数据库如何保证先查询后插入/更新 原子性?

2024-08-20 22:18

本文主要是介绍业务需求:数据库如何保证先查询后插入/更新 原子性?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、业务需求:

当操作积分用户表时,如果accountId在表中没有数据,那么我们新增一条数据,设置用户积分。如果accountId在表中有数据,我们需要更新用户积分。
这个操作简单来说就是: 
在单线程下 我们先查询后处理当然没有问题,但是在并发下问题就显而易见了,系统里可能同时插入两条一样的accountId数据。

二、问题解决:

解决方式一: ON DUPLICATE KEY UPDATE
数据库中account_id设置唯一索引,当发现account__id已经存在时,会执行update操作,不存在时会执行insert操作。
一行sql语句就能完成两种操作,保证了原子性。
sql语句如下:
添加单元测试,查看耗时以及查验数据库在并发下数据是否正确。
代码隐去业务代码,如下:
查看打印的日志,共耗时:22690ms
数据库数据能够保持正确性
解决方式二: 使用分布式锁
这个耗时比第一种方式差很多,所以没有测试完就放弃了。
因为高并发的情况下 锁的抢占很激烈,这里很多时间都耗费在锁的抢占上,没有抢占到锁的线程需要重试而不能失败,类似于CAS操作,所以这种方式不适合当前业务。
解决方式三: INSERT INTO SELECT
此种方式也是最优的,耗时:20010ms
sql语句如下:
查询accountId不存在时结果:
查询accountId存在时结果:
这里需要注意的是,此sql语句在Mapper.xml中是insert语句:

三、原理分析

1、ON DUPLICATE KEY UPDATE
mysql "ON DUPLICATE KEY UPDATE" 语法:
如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则在出现重复值的行执行UPDATE;如果不会导致唯一值列重复的问题,则插入新行。
2、 INSERT INTO SELECT
INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中。目标表中任何已存在的行都不会受影响。
其中使用到了dual虚拟表, 根据mysql的官方定义:
DUAL is purely for the convenience of people who require that all SELECT statements should have FROM and possibly other clauses. MySQL may ignore the clauses. MySQL does not require FROM DUAL if no tables are referenced.
官方的解释说:纯粹是为了满足select … from…这一习惯问题,mysql会忽略对该表的引用。所以上面的语句from dual可以去掉。
简言之,from dual完全是一个可有可无的东西。只是为了方便使用select 语句中喜欢带上from的开发者。
例如我们使用select 1 查询等价于select 1 from dual

四、总结

到了这里就分析完了,如果大家有更好的解决方案也可以拿出来学习下,文中如有问题恳请大家指正一下。
第一种方式会有一个id不是连续自增的问题,具体可以参考文章: https://segmentfault.com/a/1190000017268633

这篇关于业务需求:数据库如何保证先查询后插入/更新 原子性?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091324

相关文章

MySQL中的交叉连接、自然连接和内连接查询详解

《MySQL中的交叉连接、自然连接和内连接查询详解》:本文主要介绍MySQL中的交叉连接、自然连接和内连接查询,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、引入二、交php叉连接(cross join)三、自然连接(naturalandroid join)四

mysql的基础语句和外键查询及其语句详解(推荐)

《mysql的基础语句和外键查询及其语句详解(推荐)》:本文主要介绍mysql的基础语句和外键查询及其语句详解(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋... 目录一、mysql 基础语句1. 数据库操作 创建数据库2. 表操作 创建表3. CRUD 操作二、外键

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处