MySQL主键冲突问题分析处理

news2024/9/28 17:28:38

目录

    • 背景
    • 问题分析
      • 分析数据
      • 分析代码
      • 验证分析结果
    • 原因分析
    • 验证MySQL参数
    • 解决办法
      • 修改MySQL配置参数
      • 修改代码

背景

因公司业务及预算调整,系统部署从原有云服务提供商迁移到另外一家云服务提供商,在测试新服务能力的时候,发现应用系统某个功能不能正常使用,仅仅是第一次成功。

为了分析问题,笔者使用以下环境还原报错场景进行讲解。

  • Spring Boot: 3.0.2
  • MySQL: 5.7.31
  • MyBatis: 3.5.1

问题分析

通过查看服务日志,发现后端接口报SQL异常-主键冲突,如下图所示:

刚开始看到这个错误信息,直接就懵了,怎么在另外一个服务商那里跑得好好的,到这边就主键冲突了呢。一通百度、Google之后,突然之间有个想法,会不会是这两个云服务商提供的MySQL服务,某些参数有区别。

分析数据

因为数据是迁移过来的,表中有大量旧数据,不好确定到底是那个值冲突了。

分析代码

然后查看我们代码,找到对应的PO类代码,代码类似以下,主要关注主键属性 id 的数据类型。

public class UserPo {
    private int id;
    private String name;
    private String email;
    private String password;
}

代码中发现id属性是int类型的,我们知道,Java中int类型默认值为0,在新增数据的时候并没有为id属性设置值,代码类似下面这样:

UserPo user = new UserPo();
user.setEmail("test@qq.com");
user.setName("test");
userMapper.insertUser(user);

insert方法的代码如下所示:

@Insert("insert into tb_user(id,name,email,password) values (#{user.id}, #{user.name}, #{user.email}, #{user.password})")
int insertUser(@Param("user") UserPo user);

从代码上看,应该是id值传了0,第一次数据保存成功后,以后就会发生主键冲突异常了。

验证分析结果

通过代码分析,我们去查表中确实有一条id为0的数据,类似下图所示:

在新服务器上开启应用的DEBUG日志,也在日志中查看到SQL日志中id为0的日志。

原因分析

为了查找0值可以作为主键的原因,又是一通百度、Google,最后找到了sql_mode这个参数。这个参数中有个NO_AUTO_VALUE_ON_ZERO的值。通常我们可以通过在AUTO_INCREMENT列上插入0或null值来获取下一个序列的值,但是NO_AUTO_VALUE_ON_ZERO参数阻止了0值的这种行为。也即0值将会作为一个有效的值存入id列中。
可以通过SQL Modes页面查看详细的sql_mode参数的详情,Server System Variables页面查看sql_mode简要说明。

验证MySQL参数

验证下我们分析步骤中查到的sql_mode参数的具体现象。
我们创建一张测试表tb_user,建表语句如下:

CREATE TABLE tb_user (
  id int NOT NULL AUTO_INCREMENT,
  name varchar(64) NOT NULL DEFAULT '',
  email varchar(128) NOT NULL DEFAULT '',
  password varchar(128) NOT NULL DEFAULT '',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

查看当前MySQL版本及sql_mode参数。我们看到当前的MySQL版本5.7.37,且sql_mode中没有NO_AUTO_VALUE_ON_ZERO,MySQL5.7中sql_mode默认没有NO_AUTO_VALUE_ON_ZERO参数。
在这里插入图片描述
插入两条数据看下效果

insert into tb_user values(0, 'Rock', 'rock@otc.cc', '123456');
insert into tb_user values(0, 'Kitty', 'kitty@otc.cc', '123456');

数据插入成功,且id值从1开始自增。

我们修改下sql_mode参数,在原有参数上加NO_AUTO_VALUE_ON_ZERO。

SET sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_AUTO_VALUE_ON_ZERO';

然后再插入两条数据,我们就会看到主键冲突的报错。查看数据也是有一条id为0的记录。

解决办法

修改MySQL配置参数

为了能快速在新的云平台上部署应用,并且避免出现其他的未知问题,我们首先修改了MySQL的sql_mode参数和就平台的一致。
当然我们不能通过以上命令去设置我们的MySQL服务,而是通过云服务提供商的管理平台去设置,操作麻烦一点而以。

修改代码

为了后期维护方便,将对应的实体类id属性类型改为Integer,与其他的代码保持一致。

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

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

相关文章

总结: HQL语句

总结: HQL语句 Part1 数据库的操作Part2 数据表的操作1. 创建普通表2. 内外部表3. 内外部表转换 Part1 数据库的操作 查看数据库: show databases; 创建数据库: create database if not exists 数据库名 使用数据库: use 数据库名; 查看数据库详细信息: desc database 数据库名…

通过Anaconda安装Python会得到的重要文件夹

E:\Anaconda\路径下 Scripts 文件夹:该文件夹包含了可执行的Python脚本文件,例如pip和conda等命令行工具。【pip3.exe和django-admin.exe等】Lib 文件夹:该文件夹包含了Python的标准库和其他第三方库的源代码文件。【Lib下面的site-packages…

JVM—内存可见性

什么是可见性 可见性:一个线程对共享变量值的修改,能够及时地被其他线程看到共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JMM) Java内存模型(Java Memory Model)描述了Java程序中各种…

【滑动窗口】长度最小的子数组|无重复字符的最长子串|最大连续1的个数 III|将 x 减到 0 的最小操作数

1. 长度最小的子数组 - 力扣(LeetCode) 1.题目解析: 2.算法原理 (1)方法一:暴力列举出所有的子数组的和 时间复杂度:O(n**2):枚举所有子数组O(…

Linux信号处理

Linux信号处理 什么是linux信号 本质是一种通知机制,用户 or 操作系统通过发送一定的信号,通知进程,某些事情已经发生,你可以在后续进行处理。 信号产生是随机的,进程可能正在忙自己的事情,所以&#xf…

【LVGL-按钮按钮矩阵部件】

LVGL-按钮&按钮矩阵部件 ■ LVGL-按钮部件■ 按钮部件: 点击三个按钮一个回调函数修改label值。 ■ LVGL-按钮矩阵部件■ 示例一:按钮换行,和宽度设置。■ 示例二:设置按钮宽度为2倍■ 示例三:获取点击的按钮下标&…

Deep_Learning_readme

本文目录 1.环境安装2. A1-1实验:3. A1-2实验:4. A1-3实验 :**5. A2-CNN实验****6. A3-RNN实验** !!!!!!!!提示:全程路径和环境名字不…

Linux安装Nacos

安装前必要准备 准备Java环境 ,8以上的版本,mysql(集群相关信息),nginx(进行代理) 安装Nacos 首先我们要有一个nacos的包,我们可以在线下载,也可以提前下载好&#xf…

MySQL数据库事务介绍

前言 在MySQL数据库中,事务(Transaction)是指一组SQL语句的执行序列,这些SQL语句要么全部执行成功,要么全部执行失败,保证数据库的一致性和完整性;用于操作量大、复杂度高的数据。 目录 一、…

Ubuntu 22.04安装Python3.10.13

Ubuntu最好设置为英文,我之前用中文在make的test的时候,总是会有fail。 查了下有人怀疑是language的问题,保险起见都用英文,个人实践也证明改为英文就不报错了。 issue 44031: test_embed and test_tabnanny fails if the curre…

【史上最全面arduino esp32教程】ESP32Time时间库

文章目录 前言一、安装ESP32Time库二、ESP32Time使用2.1 基础使用构造ESP32Time对象设置当前时间获取当前时间结构体 2.2 其他函数 总结 前言 欢迎来到这篇Arduino ESP32教程!在本教程中,我们将介绍ESP32Time时间库的使用。时间在许多项目中起着重要的作…

IPC网络摄像头媒体视屏流MI_VIF结构体

一个典型的IPC数据流 下图是一个典型的IPC数据流模型,流动过程如下: 1. 建立Vif->Vpe->Venc的绑定关系; 2. Sensor 将数据送入vif处理; 3. Vif 将处理后的数据写入Output Port申请的内存,送入下一级;…

docker 不同架构镜像融合问题解决

1、背景 docker 作为目前容器的标准之一,但是对于多种架构的平台的混合编译支撑不是很好。因此衍生了镜像融合,分别将多种不同的架构构建好,然后将镜像进行融合上传。拉取镜像的会根据当前系统的架构拉取不同的镜像,也可以通过 -…

Redis 不再“开源”,对中国的影响及应对方案

Redis 不再“开源”,使用双许可证 3 月 20 号,Redis 的 CEO Rowan Trollope 在官网上宣布了《Redis 采用双源许可证》的消息。他表示,今后 Redis 的所有新版本都将使用开源代码可用的许可证,不再使用 BSD 协议,而是采用…

深入理解HTTP协议本质与应用

教程介绍 HTTP是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。简单来说,如果你不懂HTTP协议,那就相当于是个只有“半桶水”的程序员。在这个课程中,带你一起花最少的时间,用最少的精力…

前端学习笔记 | Node.js

一、Node.js入门 1、什么是Node.js 定义:是跨平台JS运行环境(可以独立执行JS的环境)作用: 编写数据接口,提供网页资源功能等等前端工程化:为后续学Vue和React等框架做铺垫 2、Node.js为何能执行JS&#xff…

html第一次作业

常用标签 0, 骨架&#xff08;&#xff01;tap&#xff09; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><t…

鸿蒙预览报错 Only files in a module can be previewed

HarmonyOS第一课下载的源码无法运行&#xff0c;也无法预览&#xff0c;报错如题。 解决&#xff1a; 1、在预览页如“index.ets”文件下预览。 2、如果在通知栏看到如图提示&#xff0c;可看出是ohos/hvigor-ohos-plugin插件版本的问题&#xff0c;可点击蓝色解决方案同步并导…

Llama 2 模型

非常清楚&#xff01;&#xff01;&#xff01;Llama 2详解 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/649756898?utm_campaignshareopn&utm_mediumsocial&utm_psn1754103877518098432&utm_sourcewechat_session一些补充理解&#xff1a; 序列化&#xff…

24---DDR4电路设计

视频链接 DDR4电路设计01_哔哩哔哩_bilibili DDR4硬件电路设计 1、DDR4基本介绍 2011年1月4日&#xff0c;三星电子完成史上第一条DDR4内存。DDR4相比DDR3最大的区别有三点&#xff1a;16bit预取机制&#xff08;DDR3为8bit&#xff09;&#xff0c;同样内核频率下理论速度…