美文网首页
数据库如何保证先查询后插入/更新的原子性【转载】

数据库如何保证先查询后插入/更新的原子性【转载】

作者: 宁静的猫 | 来源:发表于2020-06-06 15:19 被阅读0次

一、业务需求:

当操作积分用户表时,如果accountId在表中没有数据,那么我们新增一条数据,设置用户积分。如果accountId在表中有数据,我们需要更新用户积分。

这个操作简单来说就是:

image

在单线程下 我们先查询后处理当然没有问题,但是在并发下问题就显而易见了,系统里可能同时插入两条一样的accountId数据。

二、问题解决:

解决方式一: ON DUPLICATE KEY UPDATE

数据库中account_id设置唯一索引,当发现account__id已经存在时,会执行update操作,不存在时会执行insert操作。

一行sql语句就能完成两种操作,保证了原子性。

sql语句如下:

image

添加单元测试,查看耗时以及查验数据库在并发下数据是否正确。

代码隐去业务代码,如下:

image

查看打印的日志,共耗时:22690ms

数据库数据能够保持正确性

解决方式二: 使用分布式锁

这个耗时比第一种方式差很多,所以没有测试完就放弃了。

因为高并发的情况下 锁的抢占很激烈,这里很多时间都耗费在锁的抢占上,没有抢占到锁的线程需要重试而不能失败,类似于CAS操作,所以这种方式不适合当前业务。

解决方式三: INSERT INTO SELECT

此种方式也是最优的,耗时:20010ms

sql语句如下:

image

查询accountId不存在时结果:

image

查询accountId存在时结果:

image

这里需要注意的是,此sql语句在Mapper.xml中是insert语句:

image

三、原理分析

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

相关文章

  • 数据库如何保证先查询后插入/更新的原子性【转载】

    一、业务需求: 当操作积分用户表时,如果accountId在表中没有数据,那么我们新增一条数据,设置用户积分。如果...

  • 微服务事务保证

    保证更新db和发送消息的事务 利用数据库的事务原子性 操作如图中所示 订单服务在更新order表的同时会将消息插入...

  • 保证缓存和数据库一致性

    如何保证缓存和数据库数据一致性呢? 1 先删除缓存 再更新数据库 线程1删除缓存 线程2查询数据 缓存没有命中,...

  • Synchronize的原子性,可见性,有序性

    转载于synchronized底层如何保证原子性、可见性、有序性_javaman_baicun 的博客-CSDN博...

  • (10)先删缓存,还是先更新DB?(2)

    一、先删缓存,再更新数据库(用得少) 双删三次操作不能保证原子性,所以很少用 1、普通不一致原因: (1)A写,删...

  • MongoDB开发之 Shell基本操作

    引子 运行 数据库 查看当前数据库: 选择数据库: 创建 执行插入操作: 查询 查询单条数据: 更新 执行查询操作...

  • volatile

    !!转载为什么volatile不能保证原子性而Atomic可以?

  • 浅谈MySQL如何保证ACID

    MySQL如何保证一致性 数据库通过原子性(A)、隔离性(I)、持久性(D)来保证一致性(C)。其中一致性是目的,...

  • kettle 知识

    kettle的正常转换速度 容易产生性能问题的场景 1. 查询类: 数据库查询:数据库查询、数据库连接、插入更新 ...

  • 高性能MYSQL数据库架构怎么玩

    转载自(田浩沛) 一、性能瓶颈产生的原因 1,关系型数据库的先天缺陷:为了保证ACID,也就是原子性,隔离性,一致...

网友评论

      本文标题:数据库如何保证先查询后插入/更新的原子性【转载】

      本文链接:https://www.haomeiwen.com/subject/yccxtktx.html