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

  遇到这种紧急需求肯定是要先明确需求和问题,需要清楚开发需要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 '' COMMENT '是否赠送(1赠送 0不赠送)',
-> `rate_type` tinyint(4) NOT NULL DEFAULT '' COMMENT '利率类型(1月利率,2年利率)',
-> `rate` int(3) NOT NULL COMMENT '利率(%)',
-> `interest_id` int(11) DEFAULT NULL COMMENT '赠送id',
-> `shop_id` int(11) NOT NULL DEFAULT '' COMMENT '商铺id',
-> `merchant_id` int(11) NOT NULL DEFAULT '' COMMENT '商户id',
-> `account_type` tinyint(4) DEFAULT '' COMMENT '赠送类型(0-卡项金,1-本金 , 2-商品)',
-> `pay_support_type` tinyint(4) DEFAULT '' 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.00', '0.00', '', '', '', '', '', '', '', '');
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值时生成新的序列号,从而生成一个内容与表中的内容不同的表那被倾倒了。

MySQL的sql_mode参数之NO_AUTO_VALUE_ON_ZERO对主键ID为0的记录影响的更多相关文章

  1. mysql日期函数及批量循环返回主键ID

    实际项目中总是会遇到各种时间计算查询等等许多时候是特别麻烦前阵子公司有个需求大致是要查询当前日期与数据库存储日期之差,本来写了个工具类调用的但是最后觉得这样不好就想着能不能用函数解决,没想到还真有这里 ...

  2. mybatis+mysql insert添加数据后返回数据主键id

    1.根据useGeneratedKeys获取返回值,部分数据库不支持 修改mybatis xml <insert id="insertUser" useGeneratedKe ...

  3. 为mysql 表重新设置自增的主键id

    1,删除原有主键: ALTER TABLE `table_name` DROP `id`; 2,添加新主键字段: ALTER TABLE `table_name` ADD `id` INT NOT N ...

  4. Mysql EF 触发器生成主键id 存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。刷新 ObjectStateManager 项 ;System.Data.Entity.Infrastructure.DbUpdateConcurrencyException

    http://stackoverflow.com/questions/24725261/how-to-use-a-custom-identity-column-in-sql-with-entity-f ...

  5. 深入浅出mybatis之返回主键ID

    目录 添加单一记录时返回主键ID 在映射器中配置获取记录主键值 获取新添加记录主键字段值 添加批量记录时返回主键ID 获取主键ID实现原理 添加记录后获取主键ID,这是一个很常见的需求,特别是在一次前 ...

  6. Oracle通过主键id删除记录很慢

    问题描述: Oracle通过主键id删除2000条记录很慢,需要花费十二分钟. 解决过程: 1.首先查看SQL的执行计划,执行计划正常,cost只有4,用到了主键索引. 2.查看等待事件, selec ...

  7. 关于mybatis用mysql时,插入返回自增主键的问题

    公司决定新项目用mybatis,虽然这个以前学过但是一直没用过都忘得差不多了,而且项目比较紧,也没时间去系统点的学一学,只好很粗略的百度达到能用的程度就行了. 其中涉及到插入实体要求返回主键id的问题 ...

  8. Mybatis+Mysql插入数据库返回自增主键id值的三种方法

    一.场景: 插入数据库的值需要立即得到返回的主键id进行下一步程序操作 二.解决方法: 第一种:使用通用mapper的插入方法 Mapper.insertSelective(record): 此方法: ...

  9. mysql 插入数据失败防止自增长主键增长的方法

    mysql设置了自增长主键ID,插入失败的那个自增长ID也加一的,比如失败5个,下一个成功的不是在原来最后成功数据加1,而是直接变成加6了,失败次数一次就自动增长1了,能不能让失败的不增长的? 或者说 ...

随机推荐

  1. Apache损坏无法使用怎么办

    已经 find / -name httpd | xargs rm -rf删光了httpd相关文件,但是使用yum install httpd 无法正常安装. 查看Httpd的状态是 解决办法: yum ...

  2. 如何设置payjs的微信jsapi支付目录

    首先你得是 payjs 的有效开通用户.不清楚 payjs 是干什么的可以自行百度. 设置方法非常简单,在后台菜单-系统设置-JSAPI目录设置,在右侧填写支付目录即可. 需要注意的是:支付目录需要配 ...

  3. Ultimate Guide to Line For Business (May 2019)

    Ultimate Guide to Line For Business (May 2019) By Iaroslav Kudritskiy February 4, 2019 No Comments I ...

  4. 什么是梯度下降法与delta法则?

    梯度下降法就是沿梯度下降的方向求解函数(误差)极小值.delta法则是使用梯度下降法来找到最佳权向量.拿数字识别这个案例为例,训练模型的过程通常是这样的.输入为1万张图片,也就是1万个样本,我们定义为 ...

  5. 最新 科大讯飞java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.科大讯飞等10家互联网公司的校招Offer,因为某些自身原因最终选择了科大讯飞.6.7月主要是做系统复习.项目复盘.Leet ...

  6. 解决java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

    解决java.lang.SecurityException: Invalid signature file digest for Manifest main attributes 当项目依赖其他jar ...

  7. Upgrading CentOS 6 to CentOS 7

    Upgrading CentOS 6 to CentOS 7 November 15th, 2018 — whplus PRE TASKS There are some tasks you can d ...

  8. web前端页面解决中文传参乱码问题

    问题背景:在项目中往往会涉及到前端跳转页面时要传一些参数给下一个页面,如果参数是英文或者数字的时候就很好解决,然而有时候传参会涉及到中文汉字,这个时候再单纯的拼接往往就会导致中文乱码,下面我们就该讨论 ...

  9. MyBatis学习存档(4)——进行CRUD操作

    使用MyBatis进行数据库的CRUD操作有2种方式:一种如之前所说的接口+xml,而另一种是通过对接口上的方法加注解(@Select @Insert @Delete @Update) 但是通常情况下 ...

  10. Spring实战(一)Spring简介---呕心沥血只为让Java开发更简单。

    Spring诞生的初衷是为了替代更加重量级的企业级Java技术(EJB). 相对于EJB来说,Spring提供了更加轻量级和简单的编程模型,它增强了POJO(简单老式Java对象)的功能,使简单的Ja ...