1.背景
最后在公司的后臺(tái)系統(tǒng)上遇到了一個(gè)線上問題,是在插入某個(gè)表數(shù)據(jù)的時(shí)候出現(xiàn)了數(shù)據(jù)庫(kù)的插入異常,即:java.sql.SQLException: Field 'xxx' doesn't have a default value
,這其實(shí)是一個(gè)比較常見的異常,一般在字段不能為null時(shí),如果沒有顯式的指定對(duì)應(yīng)字段的值就會(huì)拋出這個(gè)異常。
但是今天遇到的這個(gè)異常原因還不是這樣的,實(shí)際原因有點(diǎn)隱蔽,所以在這里記錄一下今天遇到的這個(gè)問題。
2.問題處理
下面以一張Demo
表為例來進(jìn)行說明,有一個(gè)可以為null的字段與一個(gè)不能為null的字段。
create table demo
(
id bigint auto_increment comment '主鍵' primary key,
name varchar(64) null comment '名稱',
status tinyint not null comment '狀態(tài)'
);
問題排查:
就像在背景中提到的,當(dāng)字段不能為null時(shí),很容易觸發(fā)上述的異常,于是在第一時(shí)間檢查DDL
,發(fā)現(xiàn)字段name
可以為空。這就奇怪了,正常情況下不會(huì)出現(xiàn)這個(gè)問題,于是懷疑這種可以為空的字段,在某種特殊情況會(huì)導(dǎo)致沒有默認(rèn)值的異常。
于是通過搜索引擎和GPT提出了我的問題,當(dāng)時(shí)問題聚焦于null和非null字段上,得到的結(jié)果基本上都指向了可以為null的字段不會(huì)出現(xiàn)這個(gè)問題。
轉(zhuǎn)換思路:
搜索無(wú)果后,嘗試轉(zhuǎn)換了一下思路,再重新關(guān)注一下問題的描述 Field 'xxx' doesn't have a default value
,當(dāng)時(shí)靈光一閃,提示已經(jīng)非常清晰了沒有默認(rèn)值。經(jīng)過測(cè)試發(fā)現(xiàn),在建表和新增字段的時(shí)候,對(duì)于可以為null的字段,即使是沒有顯示的指定一個(gè)deafult
,也會(huì)自動(dòng)分配一個(gè)默認(rèn)值null
。
也就是說,下面兩個(gè)ddl
是等價(jià)的。
# 不顯示指定默認(rèn)值
alter table demo
add age int null comment '年齡';
# 顯示指定默認(rèn)值null
alter table demo
add age int null comment '年齡' default null;
既然問題沒有出現(xiàn)在字段的創(chuàng)建上,那多半是后期在對(duì)數(shù)據(jù)庫(kù)修數(shù)的時(shí)候,刪除了字段的默認(rèn)值。于是去查看了一下數(shù)據(jù)庫(kù)的工單申請(qǐng)列表,果然發(fā)現(xiàn)了端倪,有這么一個(gè)ddl
:
alter table demo
alter column name drop default;
問題復(fù)現(xiàn):
嘗試在測(cè)試環(huán)境執(zhí)行這條sql
,并通過insert
語(yǔ)句在不顯示指定name
字段的情況下,插入一條數(shù)據(jù):
insert into demo (status) values ( 1);
執(zhí)行結(jié)果如下:
問題解決:
問題已經(jīng)定位復(fù)現(xiàn)后,再重新設(shè)置字段的默認(rèn)值即可:
alter table demo
alter column name set default null;
3.思考與總結(jié)
就像標(biāo)題上說的,這個(gè)問題的隱蔽之處在于,即使是將字段的默認(rèn)值drop
了,在各類可視化界面中也看不出來,例如下圖紅框中的字段,其中name
沒有默認(rèn)值,age
字段有默認(rèn)值null
,但是根本看不出來:
這種情況可以,可以使用SHOW CREATE TABLE demo;
獲取原始的建表語(yǔ)句:
CREATE TABLE `demo` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(64) COMMENT '名稱',
`status` tinyint(4) NOT NULL COMMENT '狀態(tài)',
`age` int(11) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4
這里就可以看到name
和age
字段的默認(rèn)值區(qū)別了。
最后是一些思考和總結(jié):文章來源:http://www.zghlxwxcb.cn/news/detail-821655.html
- 如果沒有顯式的指定字段默認(rèn)值,在創(chuàng)建字段的時(shí)候會(huì)自動(dòng)將默認(rèn)值指定為
null
。 -
not null
字段,無(wú)法自動(dòng)指定默認(rèn)值,需要顯示的指定。 - 可以使用
SHOW CREATE TABLE demo;
查看原始的建表語(yǔ)句,能直接看到默認(rèn)值是否存在。
最后,如果需要修改默認(rèn)值,將期設(shè)置為一個(gè)具體的值(哪怕設(shè)置為null
),盡可能的不要使用drop default
刪除字段默認(rèn)值,以此來避免一些意料之外的問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-821655.html
到了這里,關(guān)于【MySQL實(shí)踐】一個(gè)隱蔽的問題導(dǎo)致 Field ‘xxx‘ doesn‘t have a default value的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!