mysql报错 DuplicateKeyException分析与解决

在做数据库同步的时候,发现一个错误,mysql报错如下:

org.springframework.dao.DuplicateKeyException:
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:XXX
### The error may involve com.jd.medicine.b2c.trade.center.daoHistory.RxOrderHistoryDao.addRxOrder-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO XXX (... ) VALUES ( ? ,? ,? )
### Cause: error: code = AlreadyExists desc = Duplicate entry 'XXXXX' for key 'PRIMARY' (errno 1062) (sqlstate 23000) during query: insert into XXX( ...) values (...); 
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:245)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:71)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:364)
at com.sun.proxy.$Proxy17.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:236)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:46)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:43)
at com.sun.proxy.$Proxy25.addRxOrder(Unknown Source)
...
... 49 common frames omitted

根据报错信息得知,这个错误是因为相同主键重复插入导致的
想到我的业务逻辑是:实时同步数据库(A库主数据,实时同步到B库)
1.实时接收A库的变化,一有变化就接收binlog;
2.根据binlog的主键,先查询B库有没有这条数据,有就修改,没有就插入,
问题就在第二步,如果并发极高,两条相同的binlog同时过来,
第一条来了先查询B库,没有发现这条数据,执行插入操作,正常,
就在此时,第二条binlog也来了,此时第一条还没有插入成功,所以此时查询B库,结果还是没有这条数据,
然后就执行插入操作,
此时其实B库中是已经插入这条数据的,所以第二次插入就会报错,相同主键重复插入.

解决思路:

方案1:

通过业务端,将并发量减少就可以了,
比如已知一条数据插入的时间间隔是10-20ms;那么就在插入前的查询判断,让线程sleep一个随机的时间(20ms<time<30ms),
我们知道,让线程sleep,会增加cup的使用,如果cpu比较紧张,这并不是一个很好的方法,
但是如果你的系统可以动态的增加机器,那么线程sleep就不是什么问题了.

方案2:

每次插入的时候,在redis中缓存一下,设置过期时间,比如说设置成1秒,
然后每次插入前都查一下redis,如果能查到值,那么就证明本条数据是插入过的,这样也可以防重
但是这样会引入第三方redis,这个就是分布式常说的问题了,还要考虑redis宕机的情况

方案3:

使用mysql的函数,下面这段是在网上找的,基本思路是让mysql自己消化这种问题,仅供参考:

1.insert ignore into 
当插入数据时,如出现错误时,如重复数据,将不返回错误,只以警告形式返回。所以使用ignore请确保语句本身没有问题,否则也会被忽略掉。例如: 
INSERT IGNORE INTO books (name) VALUES ('MySQL Manual') 
这种方法很简便,但是有一种可能,就是加入不是因为重复数据报错,而是因为其他原因报错的,也同样被忽略了~2.on duplicate key update 
当primary或者unique重复时,则执行update语句,如update后为无用语句,如id=id,则同1功能相同,但错误不会被忽略掉。例如,为了实现name重复的数据插入不报错,可使用一下语句: 
INSERT INTO books (name) VALUES ('MySQL Manual') ON duplicate KEY UPDATE id = id 
这种方法有个前提条件,就是,需要插入的约束,需要是主键或者唯一约束(在你的业务中那个要作为唯一的判断就将那个字段设置为唯一约束也就是unique key)。3.insert … select … where not exist 
根据select的条件判断是否插入,可以不光通过primary 和unique来判断,也可通过其它条件。例如: 
INSERT INTO books (name) SELECT 'MySQL Manual' FROM dual WHERE NOT EXISTS (SELECT id FROM books WHERE id = 1) 
这种方法其实就是使用了mysql的一个临时表的方式,但是里面使用到了子查询,效率也会有一点点影响,如果能使用上面的就不使用这个。4.replace into 
如果存在primary or unique相同的记录,则先删除掉。再插入新记录。 
REPLACE INTO books SELECT 1, 'MySQL Manual' FROM books 
这种方法就是不管原来有没有相同的记录,都会先删除掉然后再插入。

我最终的解决方法

由于我的项目这个操作是通过消费mq消息来insert的.那么就算是报错,mq也会重试的,
下次重试的时候,就可以查到B库是有数据的,所以就正常处理了,也没有报错了,
所以即使我不处理,也不会影响系统数据,
之所以把这个抛出来,是因为系统对sql设置了报警,我是不想让这种情况一直报警

考虑到要尽量少的依赖redis等第三方,所以方案2pass掉了
业务很有可能变化.如果在业务上做太多判断,以后更改业务就会无意的在这块留下坑,所以方案1也pass.

最终用了方案3的第一种,insert ignore into

如果确实是ignore了,业务返回是0,将这种情况特殊处理,比如重新操作一遍,就不会有上述问题了
至此,转了一大圈,问题解决!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[运维]---linux机器一般监控用到的概念记录

发布在linux上的机器,一般我们需要监测各项数据来证实服务器是没问题的, 如果出现问题,我们也可以通过以下指标找到问题的方向 容器指标硬件指标磁盘指标系统指标网络指标 容器指标 线程数 -当前容器内线程总数&#xff08;平均到每个核的线程数&#xff09;进程数 -当前容器…

SHA算法原理

一、SHA1算法简介 安全哈希算法&#xff08;Secure Hash Algorithm&#xff09;主要适用于数字签名标准&#xff08;Digital Signature Standard DSS&#xff09;里面定义的数字签名算法&#xff08;Digital Signature Algorithm DSA&#xff09;。对于长度小于2^64位的消息&am…

[数据库]---mysql 插入sql之 INSERT INTO和INSERT IGNORE INTO和REPLACE INTO和ON DUPLICATE KEY UPDATE比较应用

mysql插入一条数据方式有四种,接下来逐个说明验证: 前提: 有一个表,作为本次测试: CREATE TABLE zs_test (id int(11) NOT NULL AUTO_INCREMENT,order_id int(11) DEFAULT NULL,name varchar(255) DEFAULT NULL,PRIMARY KEY (id),UNIQUE KEY order_id_index (order_id) ) EN…

DES加密算法原理

一、DES算法理论 本世纪五十年代以来&#xff0c;密码学研究领域出现了最具代表性的两大成就。其中之一就是1971年美国学者塔奇曼 &#xff08;Tuchman&#xff09;和麦耶&#xff08;Meyer&#xff09;根据信息论创始人香农&#xff08;Shannon&#xff09;提出的「多重加密有…

[python]---从java到python(01)---基础与入门上手

前言 我本是java派的,已经有几年了,直接也接触过其他语言,比如从最早的汇编语言到高级语言始祖的C; 但是近来越发觉得python很火,现在以我的视角开始写入门python基础,算是入坑了; 我的计划是这个系列要更契合那些有java基础的同胞们,用你们已有的java基础,用对比的方式,更快的…

AES加密算法原理

一、摘要 AES&#xff08;The Advanced Encryption Standard&#xff09;是美国国家标准与技术研究所用于加密电子数据的规范&#xff0c;在2002年5月26日建立。它被预期能成为人们公认的加密包括金融、电信和政府数字信息的方法。AES 是一个新的可以用于保护电子数据的加密算法…

java获取本机ipv4,并使用Google Guava 缓存

java写个util,获取本机ip,并使用Google Guava 缓存起来 四个方法: 获取本机ipv4ip转16进制16进制转ip校验ip 首先,Google Guava使用的maven配置 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version&g…

OpenSSL库概述

一、背景技术SSL是Secure Sockets Layer&#xff08;安全套接层协议&#xff09;的缩写&#xff0c;可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时&#xff0c;提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户…

短信微信等消息发送系统的架构设计

消息发送系统 项目中的一种做法,简化总结如下 1.对外暴露接口1,供业务方调用 2.接口2的实现就是同步发送各种消息,比如发短信,发微信等,但不保证 3.对外暴露接口2,供业务方调用 4.接口2内部实现,也是发送消息,但是是通过mq解耦的 4.1.业务方调用接口2后,接口2的实现将会发送一…

大数运算库简介

一、技术背景在网络安全技术领域中各种加密解密算法的软件实现上始终有一个共同的问题就是如何在普通的 PC 机上实现大数的运算。我们日常生活中所应用的 PC 机内部字长多是32 位或 64 位&#xff0c;但是在各种加密解密的算法中为了达到一定的安全强度&#xff0c;都是要求在1…

内存溢出,频繁full gc 处理思路

内存溢出,频繁full gc 处理思路 1.导出整个JVM 中内存信息 jmap -dump:formatb,file文件名 [pid] 2.分析dump文件的两种方式: 2.1. jdk安装目录下,bin目录下,jvisualvm.exe双击打开 文件–装入–选择dump出来的文件 就可以开始分析了2.2. 使用eclipse,安装插件mat(MemoryAn…

Base64编码解码原理

一. Base64编码由来 为什么会有Base64编码呢&#xff1f;因为有些网络传送渠道并不支持所有的字节&#xff0c;例如传统的邮件只支持可见字符的传送&#xff0c;像ASCII码的控制字符就不能通过邮件传送。这样用途就受到了很大的限制&#xff0c;比如图片二进制流的每个字节不可…

eclipse mat 打开dump文件,明明大小1G,打开后却只有不到100M.其他的去哪了

eclipse mat 打开dump文件,明明大小1G,打开后却只有不到100M.其他的去哪了 Used heap dump 显示的大小远小于dump文件大小 解决: window-->Preferences-->memory Analuzer-->勾选keep unreachable objects-->apply and close

MVP模式介绍

一、概述MVP 是从经典的模式MVC演变而来&#xff0c;它们的基本思想有相通的地方&#xff1a;Controller/Presenter负责逻辑的处理&#xff0c;Model提供数据&#xff0c;View负责显示。二、MVC和MVP的区别作为一种新的模式&#xff0c;MVP与MVC有着一个重大的区别&#xff1a;…

eclipse mat 分析dump文件,打开文件报错,out of memeory

eclipse mat 分析dump文件,打开文件报错,out of memeory 解决: 1.打开eclipse报out of memeory通用 window-->Preferences-->java-->installed JREs-->选中-->edit--> 在default VM arguments栏中加入:-server -Xms4096m -Xmx4096m -XX:PermSize512m -XX:M…

VIPER模式介绍

一、概述VIPER模式的理念不属于MV(X)系类&#xff0c;其理念来自于建筑设计。建筑领域流行这样一句话&#xff0c;“我们虽然在营造建筑&#xff0c;但建筑也会重新塑造我们”。正如所有开发者最终领悟到的&#xff0c;这句话同样适用于构建软件。编写代码中至关重要的是&#…

mysql索引(b+tree)小记

索引:快速检索的数据结构,缺点是插入时要创建索引树,所以索引不能太多 1.hash O(1) 时间复杂度低 有冲突,不支持范围查询,不支持排序 2.二叉树BST 平衡树:O(logn) 缺点:当树不平衡时,相对于没有索引 3.红黑数 相对二叉树,相对平衡 插入逐渐增大时,也会有右倾,也不是很平衡…

强制消除Xcode警告的方法

比如我已经知道某行会报警告了&#xff0c;但是代码有这么写的道理&#xff0c;实在不想看到警告&#xff0c;可以用下面这个宏把这几行代码包住&#xff0c;就可以消除警告了。#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wunused-variable"/…

springMVC 源码级别总结原理,DispatcherServlet核心方法

前言 springMVC自我总结 本次maven: <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.3.…

SQLite3中的数据类型

一、概述 大多数的数据库引擎&#xff08;到现在据我们所知的除了sqlite的每个sql数据库引擎&#xff09;都使用静态的、刚性的类型&#xff0c;使用静态类型&#xff0c;数据的类型就由它的容器决定&#xff0c;这个容器是这个指被存放的特定列。 Sqlite使用一个更一般的动态类…