热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL的sql_mode参数之NO_AUTO_VALUE_ON_ZERO对主键ID为0的记录影响

最近遇到一个不合理使用数据库进行项目开发最终导致项目进度受阻的一个问题,某天几位开发人员找到我并告知数据库中某张表数据无法写入,又告知某行记录被删除了,因为被删除的记录对开发框架影响很大,他们已尝

  最近遇到一个不合理使用数据库进行项目开发最终导致项目进度受阻的一个问题,某天几位开发人员找到我并告知数据库中某张表数据无法写入,又告知某行记录被删除了,因为被删除的记录对开发框架影响很大,他们已尝试重新写入但无法生效并以为是表坏了(有时候你以为的就真的只是你以为)。

  遇到这种紧急需求肯定是要先明确需求和问题,需要清楚开发需要DB支持什么。最终才明白某几张表中的起始数据被插入ID为0的记录,这个与我们经常说的自增ID起始为1不符合,明显是不符合数据库开发规范的。数据删除容易,恢复起来真的不容易,还是恢复一条不规范的数据库需求,由于现象比较特殊且是历史问题,优化不易暂且先恢复(这里强烈不建议插入ID为0的数据记录)。

#表结构如下
CREATE
TABLE `xx_xxxx_xxxx` ( -> `id` int(11) NOT NULL AUTO_INCREMENT, -> `deposit_name` varchar(100) NOT NULL COMMENT '存款类型名称', -> `deposit_threshold` decimal(11,2) NOT NULL COMMENT '预存门槛金', -> `deposit_interest` decimal(11,2) NOT NULL DEFAULT '0.00' COMMENT '预计赠送总额', -> `is_interest` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否赠送(1赠送 0不赠送)', -> `rate_type` tinyint(4) NOT NULL DEFAULT '2' COMMENT '利率类型(1月利率,2年利率)', -> `rate` int(3) NOT NULL COMMENT '利率(%)', -> `interest_id` int(11) DEFAULT NULL COMMENT '赠送id', -> `shop_id` int(11) NOT NULL DEFAULT '0' COMMENT '商铺id', -> `merchant_id` int(11) NOT NULL DEFAULT '0' COMMENT '商户id', -> `account_type` tinyint(4) DEFAULT '0' COMMENT '赠送类型(0-卡项金,1-本金 , 2-商品)', -> `pay_support_type` tinyint(4) DEFAULT '0' COMMENT '0 支持线下支付 1支持线下支付和线上支付', -> PRIMARY KEY (`id`) -> ) ENGINE=InnoDB;

#查询数据(排查表损坏的可能)
  select max(id) from xx_xxxx_xxxx;

#插入删除的记录
mysql> INSERT INTO `xx_xxxx_xxxx` (`id`, `deposit_name`, `deposit_threshold`, `deposit_interest`, `is_interest`, `rate_type`, `rate`, `interest_id`, `shop_id`, `merchant_id`, `account_type`, `pay_support_type`) VALUES ('0', '普通会员(无权益)', '0.00', '0.00', '1', '2', '0', '1', '0', '0', '0', '0');
Query OK, 1 row affected (0.14 sec)

#查询刚才的记录(没有结果集返回)
select id,deposit_name from xx_xxxx_xxxx where id = 0;

   查询和写入操作都进行了,并且都返回了正常的结果集,排查了开发以为的表损坏无法写入的问题(如果表有损坏一般业务群或者开发群早炸锅了)。但是有一个奇怪的现象,为什么数据正常写入了但就是查不到ID为0的记录?既然ID查找不到,对于已经写入的数据也可以用其他字段值查找,最终找到了这条记录,但它的ID不是0而是当前表中的max(id)。为什么会出现这种情况呢?查看官方文档才发现这个与sql_mode有关,MySQL对于插入ID为NULL或者0的记录会使用自增的策略分配ID。

  但是对于ID为0的记录不能直接写入,但是我们可以updateID的值,保证这行记录能顺利存在。

mysql> INSERT INTO `xx_xxxx_xxxx` (`id`, `deposit_name`, `deposit_threshold`, `deposit_interest`, `is_interest`, `rate_type`, `rate`, `interest_id`, `shop_id`, `merchant_id`, `account_type`, `pay_support_type`) VALUES ('0', '普通会员(无权益)', '0.00', '0.00', '1', '2', '0', '1', '0', '0', '0', '0');
Query OK, 1 row affected (0.14 sec)

mysql> select * from xx_xxxx_xxxx;
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
| id | deposit_name                | deposit_threshold | deposit_interest | is_interest | rate_type | rate | interest_id | shop_id | merchant_id | account_type | pay_support_type |
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
|  1 | 普通会员(无权益)          |              0.00 |             0.00 |           1 |         2 |    0 |           1 |       0 |           0 |            0 |                0 |
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
1 row in set (0.00 sec)

mysql> update xx_xxxx_xxxx set id = 0 where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from xx_xxxx_xxxx;                
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
| id | deposit_name                | deposit_threshold | deposit_interest | is_interest | rate_type | rate | interest_id | shop_id | merchant_id | account_type | pay_support_type |
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
|  0 | 普通会员(无权益)          |              0.00 |             0.00 |           1 |         2 |    0 |           1 |       0 |           0 |            0 |                0 |
+----+-----------------------------+-------------------+------------------+-------------+-----------+------+-------------+---------+-------------+--------------+------------------+
1 row in set (0.00 sec)

总结:

#MySQL 5.7的sql_mode值
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, and NO_ENGINE_SUBSTITUTION

  因为在数据库表中ID采用了自增ID策略。默认情况下当ID是0或者null的时候,数据库会自动产生一个新的自增序列作为这条记录的ID。这就是我们插入0值ID记录时与期望不符原因。

  如果想让自增列在只插入null的时候产生自增序列,就要提前设置mysql的sql_mode包括NO_AUTO_VALUE_ON_ZERO。

  如果您使用mysqldump转储表然后重新加载它,MySQL通常会在遇到0值时生成新的序列号,从而生成一个内容与表中的内容不同的表那被倾倒了。


推荐阅读
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文详细介绍了如何使用Linux下的mysqlshow命令来查询MySQL数据库的相关信息,包括数据库、表以及字段的详情。通过本文的学习,读者可以掌握mysqlshow命令的基本语法及其常用选项。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 在AngularJS中,有时需要在表单内包含某些控件,但又不希望这些控件导致表单变为脏状态。例如,当用户对表单进行修改后,表单的$dirty属性将变为true,触发保存对话框。然而,对于一些导航或辅助功能控件,我们可能并不希望它们触发这种行为。 ... [详细]
  • 我在尝试将组合框转换为具有自动完成功能时遇到了一个问题,即页面上的列表框也被转换成了自动完成下拉框,而不是保持原有的多选列表框形式。 ... [详细]
  • 在使用mybatis进行mapper.xml测试的时候发生必须为元素类型“mapper”声明属性“namespace”的错误项目目录结构UserMapper和UserMappe ... [详细]
  • Java连接MySQL数据库的方法及测试示例
    本文详细介绍了如何安装MySQL数据库,并通过Java编程语言实现与MySQL数据库的连接,包括环境搭建、数据库创建以及简单的查询操作。 ... [详细]
  • 本文介绍了如何通过创建自定义 XML 文件来修改 Android 中 Spinner 的项样式,包括颜色和大小的调整。 ... [详细]
  • 使用R语言进行Foodmart数据的关联规则分析与可视化
    本文探讨了如何利用R语言中的arules和arulesViz包对Foodmart数据集进行关联规则的挖掘与可视化。文章首先介绍了数据集的基本情况,然后逐步展示了如何进行数据预处理、规则挖掘及结果的图形化呈现。 ... [详细]
  • Kubernetes Services详解
    本文深入探讨了Kubernetes中的服务(Services)概念,解释了如何通过Services实现Pods之间的稳定通信,以及如何管理没有选择器的服务。 ... [详细]
  • 本文详细介绍了PHP中的几种超全局变量,包括$GLOBAL、$_SERVER、$_POST、$_GET等,并探讨了AJAX的工作原理及其优缺点。通过具体示例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 本文详细介绍了在MyBatis框架中如何通过#和$两种方式来传递SQL查询参数。使用#方式可以提高执行效率,而使用$则有助于在复杂SQL语句中更好地查看日志。此外,文章还探讨了不同场景下的参数传递方法,包括实体对象、基本数据类型以及混合参数的使用。 ... [详细]
  • 本文介绍如何通过mysqladmin ext命令监控MySQL数据库的运行状态,包括性能指标的实时查看和分析。 ... [详细]
  • 2023年1月28日网络安全热点
    涵盖最新的网络安全动态,包括OpenSSH和WordPress的安全更新、VirtualBox提权漏洞、以及谷歌推出的新证书验证机制等内容。 ... [详细]
  • 本文深入探讨了MySQL中的高级特性,包括索引机制、锁的使用及管理、以及如何利用慢查询日志优化性能。适合有一定MySQL基础的读者进一步提升技能。 ... [详细]
author-avatar
花谢五月天
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有