概述
在使用MySQL + MyBatis時(shí)遇到的問(wèn)題,記錄一下。
問(wèn)題
在測(cè)試環(huán)境里,往MySQL數(shù)據(jù)表里插入數(shù)據(jù)時(shí)報(bào)錯(cuò):SQLIntegrityConstraintViolationException: Column 'create_time' cannot be null
表結(jié)構(gòu)字段定義:
create_time datetime default CURRENT_TIMESTAMP not null comment '創(chuàng)建日期',
備注:
MySQL數(shù)據(jù)庫(kù)版本:
select version();
5.7.30
使用的MyBatis版本:
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.3</version>
</dependency>
使用的MySQL驅(qū)動(dòng)版本:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
排查
參考mysql-insert-error-cannot-be-null-datetime-not-null-default-current-timestamp。
給出的解釋是:
The MySQL 5.7 manual states that…
In addition, you can initialize or update any TIMESTAMP column to the current date and time by assigning it a NULL value, unless it has been defined with the NULL attribute to permit NULL values.
The manual does not say you can do this for DATETIME fields.
簡(jiǎn)單翻譯下,就是TIMESTAMP字段能夠?qū)崿F(xiàn)插入當(dāng)前時(shí)間,datetime字段則不一定能保證。
修改測(cè)試環(huán)境下的表結(jié)構(gòu)定義語(yǔ)句:
create_time timestamp default CURRENT_TIMESTAMP not null comment '創(chuàng)建日期',
stackoverflow還是非??孔V,問(wèn)題解決。
datetime & timestamp
相同:都可以表示YYYY-MM-DD HH:MM:SS
這種年月日時(shí)分秒格式的數(shù)據(jù)。MySQL5.6.4之前,都不能表示小數(shù)。MySQL5.6.4后這兩者都可以包含秒后的小數(shù)部分,精度最高為微妙(6位)
不同:
- 存儲(chǔ)范圍
datetime的存儲(chǔ)范圍是1000-01-01 00:00:00.000000
到9999-12-31 23:59:59.999999
,而timestamp的范圍是1970-01-01 00:00:01.000000
到2038-01-19 03:14:07.999999
(準(zhǔn)備的來(lái)講應(yīng)該是UTC范圍); - 時(shí)區(qū)
datetime存儲(chǔ)與時(shí)區(qū)無(wú)關(guān)(準(zhǔn)備來(lái)說(shuō)是datetime只支持一個(gè)時(shí)區(qū),即存儲(chǔ)時(shí)當(dāng)前服務(wù)器的時(shí)區(qū)),而timestamp存儲(chǔ)的是與時(shí)區(qū)有關(guān)。
MySQL在存儲(chǔ)TIMESTAMP時(shí),會(huì)先將時(shí)間從當(dāng)前服務(wù)器的時(shí)區(qū)轉(zhuǎn)換為UTC(世界協(xié)調(diào)時(shí))以進(jìn)行存儲(chǔ),然后查詢時(shí)從UTC轉(zhuǎn)換為當(dāng)前時(shí)區(qū)以進(jìn)行返回。也就是說(shuō)使用timestamp進(jìn)行存儲(chǔ)的時(shí)間返回的時(shí)候會(huì)隨著數(shù)據(jù)庫(kù)的時(shí)區(qū)而發(fā)生改變。而datetime的存儲(chǔ)則與時(shí)區(qū)無(wú)關(guān),數(shù)據(jù)是什么就存儲(chǔ)什么,也就返回什么 - 存儲(chǔ)大小
在5.6.4之前,datetime存儲(chǔ)占用8個(gè)字節(jié),而timestamp是占用4字節(jié);但是在5.6.4之后,由于這兩個(gè)類型允許有小數(shù)部分,所以占用的存儲(chǔ)空間和以前不同;
MySQL規(guī)范規(guī)定,datetime的非小數(shù)部分需要5個(gè)字節(jié),而不是8個(gè)字節(jié),而timestamp的非小數(shù)部分是需要4個(gè)字節(jié),并且這兩個(gè)部分的小數(shù)部分都需要0到3個(gè)字節(jié),具體取決于存儲(chǔ)值的小數(shù)秒精度
反思
除上面的create_time
字段在insert到數(shù)據(jù)庫(kù)時(shí)沒(méi)有設(shè)置系統(tǒng)當(dāng)前時(shí)間,另外還有一個(gè)字段is_delete
也有類似問(wèn)題:
is_delete int(1) default 0 null comment '是否刪除 0-未刪除 1-已刪除',
理論上代碼層面沒(méi)有設(shè)置is_delete
時(shí),落到數(shù)據(jù)庫(kù)時(shí)使用default
值,即0。
這就很懵逼啊,代碼就那么幾行。
突然發(fā)現(xiàn)使用的時(shí)MyBatis的insert方法,而沒(méi)有使用insertSelective方法。
insert & insertSelective
insert這個(gè)API轉(zhuǎn)化成XML語(yǔ)法如下:
<insert id="insert">
INSERT INTO merchant_app(id,is_delete,create_time) values (#{id,jdbcType=BIGINT}, #{isDelete,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP})
</insert>
轉(zhuǎn)換成SQL如下:
INSERT INTO merchant_app(id,is_delete,create_time) VALUES( ?,?,? )
insertSelective這個(gè)API轉(zhuǎn)化成XML語(yǔ)法如下:
insert into HSP_MEDIA_INF
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null" >
id,
</if>
<if test="isDelete != null" >
is_delete,
</if>
<if test="createTime != null" >
create_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null" >
#{id,jdbcType=BIGINT},
</if>
<if test="isDelete != null" >
#{isDelete,jdbcType=INTEGER},
</if>
<if test="createTime != null" >
#{createTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
發(fā)現(xiàn)insertSelective對(duì)應(yīng)的sql語(yǔ)句加入了NULL校驗(yàn),只會(huì)插入數(shù)據(jù)不為null的字段值。insert則會(huì)插入所有字段,會(huì)插入null
INSERT INTO merchant_app(id,is_delete,create_time) VALUES( ?,?,? )
也就是說(shuō),此時(shí)即使數(shù)據(jù)表字段有default定義,遇到MyBatis的insert
方法,也無(wú)能為力。
驗(yàn)證
不再使用insert
方法,而使用insertSelective
方法,同時(shí),把數(shù)據(jù)表的TIMESTAMP類型改回為datetime類型:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-429768.html
alter table merchant_app modify create_time datetime default CURRENT_TIMESTAMP not null comment '創(chuàng)建日期';
可以插入當(dāng)前時(shí)間now()
數(shù)據(jù)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-429768.html
參考
到了這里,關(guān)于SQLIntegrityConstraintViolationException: Column ‘create_time‘ cannot be null的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!