错误起因
相同代码(将null值插入createTime列中),在移植到另一个环境时发生了
create_time cannot be null
的error,无法往下运作。在代码中临时将createTime设置为
new Date()
使之能够正常运行,但在其他地方又遇到了这个问题。
冲突点
在本地/测试/线上环境没有问题,在DDL中我们指定了:
DEFAULT CURRENT_TIMESTAMP
那么即使不指定该列,在执行DML的时候也应该有一个backup的默认值,为什么到了移植环境,相同的代码会有不同的结果?
原因
看到了这篇文章:
其实博主的解释是错误的,注释掉的部分里
explicit_defaults_for_timestamp=true
这段代码才是问题的发生关键。
执行代码
show VARIABLES like "explicit_defaults_for_timestamp"
发现本地和移植环境的结果不同:
- 本地为off
- 移植环境为on
根据 oracle官方在 dev文档中的解释如下:
explicit_defaults_for_timestamp| Command-Line Format |
--explicit-defaults-for-timestamp[={OFF|ON}]| | ------------------- | ----------------------------------------------- | | Deprecated | Yes | | System Variable |explicit_defaults_for_timestamp| | Scope | Global, Session | | Dynamic | Yes | | Type | Boolean | | Default Value |OFF|This system variable determines whether the server enables certain nonstandard behaviors for default values and
NULL-value handling inTIMESTAMPcolumns. By default,explicit_defaults_for_timestampis disabled, which enables the nonstandard behaviors.
可以知道:
- 在这个参数为off的情况下,可以将null值插入到not null 的timeStamp中,并最终赋值为对应列的默认值
- 这个参数在5.6已经被标注为Deprecated了。
- 这个参数默认是off
吐槽一下,为什么会去修改这个变量,真的属于没想到。。。
解决
临时在所有的DO2DB的代码中加入相关属性值的赋值是最保险的做法了,但是如果是hardCode强行加入的话,很有可能会有遗漏的风险,因此我们做了如下工作:
- 收集有相关case的变量
- 使用mybatis插件的方式,将补充这部分内容的代码加入到项目中,做一个整体的backup