1.背景

用多线程接收推送的订单数据,把接收的订单数据存到一个表中,实现的需求是:如果接收的订单消息在数据库中已经存在,那么执行update操作;如果没有存在,那么执行insert操作

代码逻辑:

  1. if(该订单在数据库表中存在){

  2. update();

  3. }else{

  4. insert();

  5. }

线程启动后,发现:数据库表中有两条oderid相同的记录

通过查看日志发现:

两个线程相差时间极端,各自收到了同一个订单的推送消息,在执行数据库insert或update时,都判断出该订单在数据库表中不存在,所以都执行insert操作,造成数据库表中有两条orderid相同的记录

2.解决方案

synchronized同步代码块即加同步锁,synchronized同步代码块的功能:

1)、当A线程访问对象的synchronized代码块的时候,B线程依然可以访问对象方法中其余非synchronized块的部分
       2)、当A线程进入对象的synchronized代码块的时候,B线程如果要访问这段synchronized块,那么访问将会被阻塞

  1. if(该订单在数据库表中存在){

  2. update();

  3. }else{

  4. synchronized(this){

  5. if(该订单在数据库表中存在){

  6. update();

  7. }else{

  8. insert();

  9. }

  10. }

  11. }

上面用synchronized同步代码块解决了在单点服务器中涉及到的并发问题,但是synchronized同步代码块在部署到多台服务器会失效,因为假设A机器在在执行数据库insert,判断出数据库中没有某个订单的数据,同时此刻B机器也判断出没有该订单数据,两台机器都进行insert操作,造成数据库中有重复的订单数据

3.多台服务器相互之间的并发导致有重复的订单数据问题解决

解决方案:

在数据库层面,用unique唯一性约束来保证数据的数据库表orderid的唯一性.

添加了唯一性约束后,假设A机器insert成功了,那么B机器再insert的时候会违反唯一性约束,报InvocationTargetException这个异常,捕获该异常后,进行update操作

  1. if (该订单在数据库表中存在) {

  2. update();

  3. } else {

  4. synchronized (this) {

  5. if (该订单在数据库表中存在) {

  6. update();

  7. } else {

  8. try {

  9. insert();

  10. } catch (InvocationTargetException e) {

  11. update();

  12. }

  13. }

  14. }

  15. }

来源:https://blog.csdn.net/lululove19870526/article/details/60592981

并发insert情况下会发生重复的数据插入问题相关推荐

  1. mysql基础14(关于mysql数据库在没有主键情况下去除重复数据办法)

    关于mysql数据库在没有主键情况下去除重复数据办法 约定 表名:mat 根据 cat 字段去重 新增加主键为 id 步骤 1.为mat新增一列自增主键 alter table mat add col ...

  2. Goroutine调度时机-什么时候和什么情况下会发生调度?

    原文地址:Goroutine调度时机-什么时候和什么情况下会发生调度? Go调度器会在以下三种情况对goroutine进行调度: goroutine执行某个操作因条件不满足需要等待而发生的调度. go ...

  3. 在高并发的情况下,利用redis来处理库存超卖和遗留问题

    在高并发的情况下,利用redis来处理库存超卖和遗留问题 首先现在redis中放上商品的库存数量为100间商品,在初始化一个set集合用于放秒杀成功的用户id,本用例先放进去一个id=10000的用户 ...

  4. 什么情况下会发生full Gc?如何排查频繁发生full Gc的原因?

    GC就是Java的垃圾回收机制,要了解什么情况下会发生GC(即GC得触发条件),我们需要先了解JVM的内存模型结构,之前一篇文章已经详细讲解了Jvm的内存模型结构,而通常来说,GC主要针对的是堆(ja ...

  5. cassss服务未启动_Mysql无法启动情况下,如何恢复数据呢?

    本文适用于,mysql无法启动,但数据文件未丢失的情况. Mysql因意外情况,导致无法启动,数据库未做备份的情况下,如何将数据迁移至其他数据库中. 原数据库地址:192.168.1.100(以下简称 ...

  6. Excel(WPS)使用VBA,不打开文件情况下提取其他工作簿数据

    Excel(WPS)使用VBA,不打开文件情况下提取其他工作簿数据 提取函数,返回提取到的值 使用示例 在不打开工作簿的情况下,VBA读取其他工作簿数据 很多方法需要打开才能提取,如果没打开会显示错误 ...

  7. Android 无 EditText 情况下接受扫码枪扫描数据

    2019年04月12日更新,根据评论区反馈,可能不是很好用(但是我当时用的时候就是这么实现的),可以选择性尝试 Android 无 EditText 情况下接受扫码枪扫描数据 简单无脑! 去下载个 J ...

  8. 键盘上哪个键是插入建_如何在没有插入键的情况下按键盘上的“插入”?

    键盘上哪个键是插入建 Finding a keyboard that has all the features you want can be a bit of a task at times, bu ...

  9. mysql 并发避免锁表_MYSQL锁表的用法,防止并发情况下的重复数据

    项目中有些使用的redis存储,当对redis进行rehash的时候感觉是比较麻烦的.于是写了个简单的读取redis到数据库的关键方法.仅供参考. package com.redis.web; imp ...

最新文章

  1. python matplotlib散点图-python matplotlib从函数更新散点图
  2. [Done]Spring @Pointcut 切点调用不到(SpringAOP嵌套方法不起作用) 注意事项
  3. .net 下语音合成
  4. ArcGIS 9.2 Server Pack 5 蓄势待发
  5. Spring MVC Ajax返回中文乱码
  6. 【转】刨根究底字符编码之十四——UTF-16究竟是怎么编码的
  7. Git - git tag - 查看当前分支 tag 版本说明
  8. 学习记录-操作系统知识(1)
  9. PHP整站迁移空间,Discuz! X2.5 整站搬家迁移升级教程
  10. 注册测绘师学习笔记(一)
  11. OpenCV库下载安装使用方法
  12. 微信小程序双击底部导航栏刷新页面
  13. JDK下载安装及环境变量配置的图文教程(详解)
  14. 计算机等考网络真题2018,2018年网络管理员考试试题及答案
  15. Word 题注重新编号
  16. python条件判断《X战警:逆转未来》
  17. 读《刻意练习》后感,与原文好句摘抄
  18. 真实评测 rtx3080ti对比rx6800xt选哪个好
  19. docker logs
  20. 物资学院、草房、常营点过的外卖总结

热门文章

  1. 看代码的软件_软件著作权申请中常见的补正问题及解决方式
  2. R语言——导入Excel表格数据方法
  3. python 爬取作品集_Python批量抓取站酷ZCOOL作品图片并归档
  4. HIVE时间戳错误unix_timestamp时间不同环境相差8小时
  5. 1虚拟地址,虚拟内存映射,系统调用本质,进程运行状态
  6. 在Struts2中使用ValueStack、ActionContext、ServletContext、request、session等
  7. python求斐波那契数列第n个数及前n项和_使用python求斐波那契数列中第n个数的值示例代码...
  8. linux推出mysql对话_以及如何配置它以与Linux平台上的MySQL数据库对话
  9. jQuery.parseJSON()函数详解
  10. python测试开发django-8.windows系统安装mysql8教程