數(shù)據(jù)庫Incorrect string value for column編碼異常的幾點心得

開門見山,先提出問題和解決方案

問題:Incorrect string value: '\xF0\x9F\x99\x82' for column 'device_name' at row 1; nested exception is java.sql.SQLException: Incorrect string value: '\xF0\x9F\x99\x82' for column 'device_name' at row 1

這個是java開發(fā)人員通過向數(shù)據(jù)庫插入中文或者表情符號時一個經(jīng)典的錯誤。網(wǎng)上提供的原因通常是將數(shù)據(jù)庫的編碼為gbk或其他非utf-8編碼,解決方案為將數(shù)據(jù)庫編碼改為utf-8

set character_set_client = utf8;

set character_set_server = utf8;

set character_set_connection = utf8;

set character_set_database = utf8;

set character_set_results = utf8;

set collation_connection = utf8_general_ci;

set collation_database = utf8_general_ci;

set collation_server = utf8_general_ci;

但除此之外,還有兩個原因會導致這個錯誤的發(fā)生:

原因1:

tomcat編碼和數(shù)據(jù)庫編碼不一致,windows下tomcat默認編碼為gbk,若數(shù)據(jù)庫編碼為utf-8,會導致中文無法插入

解決方案:

Tomcat啟動參數(shù)中,VM Options 增加-Dfile.encoding=UTF-8。

原因2:

數(shù)據(jù)庫字段編碼utf8_general_ci,這種編碼僅支持3字節(jié)utf-9字符,插入的內(nèi)容中含特殊符號及表情等四字節(jié)utf-8字符

解決方案:

show full columns from {table} ? ? 查看字段編碼,將需要插入表情的字符串編碼改為utf8mb4_unicode_ci

語句范例

ALTER TABLE tb_case MODIFY COLUMN content VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE tb_case MODIFY COLUMN LAST_CHAT_CONTENT VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE tb_chat MODIFY COLUMN content VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE ofoffline MODIFY COLUMN stanza TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;



借著這個機會,復習了編碼的相關知識,在這里分享一下心得。

首先介紹一下遇到這個問題的場景和解決過程,某日在排查錯誤日志時發(fā)現(xiàn),一張表的device_name字段有出現(xiàn)上述Incorrect string value的錯誤,將代碼部署在本地進行調(diào)試時,中文和表情的錯誤率卻高達100%,同樣的中文,在本地報錯的,在測試環(huán)境和生產(chǎn)環(huán)境正常。

于是排查本地環(huán)境和測試環(huán)境的區(qū)別,首先想到編碼問題,檢查確認了IDE編碼為utf-8,數(shù)據(jù)庫的編碼為utf-8

???這是什么情況,于是嘗試將\xC9\xE8\xB1\xB8?轉(zhuǎn)換成中文是否正確,結(jié)果發(fā)現(xiàn)無法使用utf-8編碼。難道這是gbk編碼,嘗試了一下發(fā)現(xiàn)果然使用gbk編碼可以轉(zhuǎn)換為中文,但我IDEA的編碼已經(jīng)全部改成utf-8了啊0 0?網(wǎng)上一搜,發(fā)現(xiàn)是tomcat編碼的問題。那生產(chǎn)環(huán)境的編碼錯誤又是什么原因呢,\xF0\x9F\x99\x82通過utf-8解碼得到一個emoji表情,查看device_name字段編碼為utf8_general_ci,不支持4字節(jié)utf8,將其改為utf8mb4_unicode_ci后問題解決。





然后對問題中的相關概念做了個總結(jié)

1.字節(jié)和字符

眾所周知,計算機世界是個二進制的世界,1字節(jié)(byte)= 8比特bit。我們看到的中文和表情是字符通過規(guī)定的編碼方式轉(zhuǎn)換為幾個字節(jié)后存儲的。

2.?\xC9\xE8\xB1\xB8 的含義

對于這樣的字符串,其實是用兩個十六進制數(shù)字來表示8bit即一個字節(jié),是屬于編碼后的字節(jié)串(字節(jié)數(shù)組),從這個串中只能得出這是4個字節(jié),無法得知其編碼方式和代表的中文或表情。

3.編碼和解碼

中文和表情的傳輸是一個編碼和解碼的過程。假設設定編碼為utf-8,在傳輸“設備”這個中文詞時,實際上傳輸?shù)臅r這個詞編碼后的四個字節(jié)

\xC9\xE8 設 ?\xB1\xB8備(16進制表示,\xC9轉(zhuǎn)換為2進制是11001001,一個字節(jié))。若發(fā)送端和接收端編碼不同,若接收端(如數(shù)據(jù)庫)嘗試以gbk對?\xC9\xE8 進行解碼,則無法獲得正確的字符報錯。

4.IDE編碼、數(shù)據(jù)庫編碼和Tomcat編碼

IDE編碼和Tomcat編碼不等同,需要保持一致,避免異常。IDE編碼決定java源碼的編碼,與數(shù)據(jù)的編碼不一致會導致插入數(shù)據(jù)時編碼異常

5.utf8和utf8mb4

utf8 是 Mysql 中的一種字符集,只支持最長三個字節(jié)的 UTF-8字符,utf8mb4支持4個字節(jié),對于部分生僻字和表情,應該使用utf8mb4

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容