explicit_defaults_for_timestamp参数导致复制中断

explicit_defaults_for_timestamp是从5.6.6引入的一个新参数,默认是off。

作用:对TIMESTAMP类型列的默认值和NULL值的处理,是否启用非标准特性。

默认情况下,explicit_defaults_for_timestamp被禁用,即启用非标准特性。

什么是非标准特性?

标准特性:如果没有显示声明为 NOT NULL,则默认声明为 NULL (除timestamp外的其他数据类型)

非标准特性:如果没有显示声明为 NULL,则默认声明为 NOT NULL(timestamp)

01

当explicit_defaults_for_timestamp=0时,默认状态,即启用非标准特性

  1. TIMESTAMP列如果没有显示声明NULL属性,则会自动加上NOT NULL属性 1)如果往这个列中插入null值,会自动的设置该列的值为current timestamp值。 2)表中的第一个TIMESTAMP列,如果没有指定null属性或者没有指定默认值,也没有指定ON UPDATE语句。那么该列会自动被加上DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP属性。 3)第一个TIMESTAMP列之后的其他的TIMESTAMP类型的列,如果没有指定null属性,也没有指定默认值,那么该列会被自动加上DEFAULT '0000-00-00 00:00:00'属性。如果insert语句中没有为该列指定值,那么该列中插入'0000-00-00 00:00:00',并且没有warning。
  2. TIMESTAMP列如果没有显式声明NOT NULL属性(或显示声明NULL属性),那么默认的该列可以为NULL 1)此时向该列中插入null值时,会直接记录null

测试1:

id=1的行,往timestamp列插入null值时,会自动为该列设置为current time

id=2的行,插入时未指定值的timestamp列中被插入了0000-00-00 00:00:00(非表中第一个timestamp列)

id=3的行,插入时未指定值的第一个timestamp列中被插入了current time值

02

当explicit_defaults_for_timestamp=1时,即启用标准特性

  1. TIMESTAMP列如果没有显式声明NOT NULL属性(或显示声明NULL属性),那么默认的该列可以为null 1)此时向该列中插入null值时,会直接记录null,而不是current timestamp值。
  2. TIMESTAMP列如果显示声明NOT NULL属性 1)没有指定默认值,此时如果向表中插入记录,但是没有给该TIMESTAMP列指定值的时候,如果strict sql_mode被指定了,那么会直接报错。如果strict sql_mode没有被指定,那么会向该列中插入'0000-00-00 00:00:00'并且产生一个warning 2)指定了默认值,除DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP外,默认值会变成'0000-00-00 00:00:00'

测试2:

id=1的行,如果timestamp列指定not null属性,在非stric sql_mode模式下,如果插入的时候该列没有指定值,那么会向该列中插入0000-00-00 00:00:00,并且产生告警

通过对 explicit_defaults_for_timestamp的了解,排查一个问题

架构如下:

现象:

二级从库复制频繁中断,一级从库正常

日志:

2017-08-18 14:17:47 357305 [ERROR] Slave SQL: Error 'Column 'modified' cannot be null' on query. Default database: 'jpos'. Query: 'insert into activity_account_sum(id,activity_id,income_number,expend_number,created,modified) values(0,584126,0,0,'2017-08-18 14:17:46',null)', Error_code: 1048
2017-08-18 14:17:47 357305 [Warning] Slave: Column 'modified' cannot be null Error_code: 1048
2017-08-18 14:17:47 357305 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.000233' position 879369308

初步分析:

通过日志信息可知,modified字段插入了null值,与表声明的not null冲突,导致错误引起复制中断。

具体分析:

  • mysql主库为5.5.38版本,一、二级从库版本为5.6.36,我们知道5.6后引入explicit_defaults_for_timestamp参数,通过查看explicit_defaults_for_timestamp=on,也就是timestamp采用的是标准特性,modified字段指定了NOT NULL并且有DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP默认值。
  • 查看表结构:
  • 查看sql mode:都没有启用stric严格模式
  • 通过以上信息可知,modified列插入null值会报错:ERROR 1048 (23000): Column 'modified' cannot be null。但是为什么一级从库没有报错呢?二级从库已获取到binlog,说明一级从库已执行完成。主库是5.5.38,比从库版本低,推断可能是出于版本兼容性考虑,在解析SQL时保持与5.5.38一致的策略,所以一级从库执行成功;二级从库与一级从库版本一致,直接使用5.6.36解析SQL的策略,所以二级从库执行失败。

解决:

  1. 修改二级从库explicit_defaults_for_timestamp=0,往timestamp数据类型列插入null值时,会自动为该列设置为current time(需要重启mysql服务后恢复)
  2. 研发修改sql,将null值修改成now()

explicit_defaults_for_timestamp跟其他参数正好相反,NULL或NOT NULL需要十分注意,最好的方式就是规范话,统一为NOT NULL 再加上默认值,即便如此,跨版本之间也容易出现问题,所以新版本上线前新引入的参数一定要有所了解,不然一不小心就会入坑。

原文发布于微信公众号 - MYSQL轻松学(learnmysql)

原文发表时间:2017-09-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏坚毅的PHP

my php & mysql FAQ

php中文字符串长度及定长截取问题使用str_len("中国") 结果为6,php系统默认一个中文字符长度为3,可改用mb_strlen函数获得长度,mb_su...

3396
来自专栏C# 编程

4 - SQL Server 2008 之 使用SQL语句删除表格

使用删除表格的SQL命令与删除数据的命令一样,只是删除的是表格这个对象, 语法如下:DROP TABLE 表名 一般在删除表格之前,需判断这个表格存不存在,存在...

1750
来自专栏ChaMd5安全团队

SQLI-LABS 更新帖(二)

Less-2 /sqli-labs/Less-2/?id=1 代码如下: $sql="SELECT * FROM users WHERE id=$id LIMI...

43210
来自专栏程序员宝库

再见乱码:5 分钟读懂 MySQL 字符集设置

作者: 程序猿小卡_casper 原文:https://segmentfault.com/a/1190000012775484 一、内容概述 在MySQL的使...

36611
来自专栏james大数据架构

C#调用SQL中的存储过程中有output参数,存储过程执行过程中返回信息

C#调用SQL中的存储过程中有output参数,类型是字符型的时候一定要指定参数的长度。不然获取到的结果总是只有第一字符。本人就是由于这个原因,折腾了很久。在此...

1837
来自专栏互联网杂技

外键约束

外键约束 foreign key 外键约束的要求: 父表和字表必须使用相同的存储引擎,禁止使用临时表; 数据库引擎只能是InnoDB; 外键列和参照列必须具有...

3359
来自专栏乐沙弥的世界

ORA-00932: inconsistent datatypes: expected - got CLOB

      最近数据库从10.2.0.3升级到了10.2.0.5之后,一些对象无法编译通过。查看了这些对象主要表现在之前写法不严格的SQL语法导致了这些pack...

823
来自专栏帘卷西风的专栏

关于mysql存储过程创建动态表名及参数处理

转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog) 

533
来自专栏小樱的经验随笔

HDU 1013 Digital Roots【字符串,水】

Digital Roots Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3276...

2574
来自专栏FreeBuf

移位溢注:告别靠人品的偏移注入

在Access数据库类型注入的时候,我们获取不到列名(前提是有表名),一般会选择使用偏移注入,但是这种注入方式往往借助的是个人的人品,且步骤繁琐。本文中我们研究...

1906

扫描关注云+社区