mysql字符集引起的java.sql.SQLException:Incorrect?string?value:問(wèn)題
問(wèn)題1
在執(zhí)行一次數(shù)據(jù)庫(kù)插入的時(shí)候,偶然發(fā)現(xiàn)的一個(gè)問(wèn)題。數(shù)據(jù)庫(kù)在插入一些生僻字,如??、??
或者emoji 表情包的時(shí)候,會(huì)出現(xiàn)如下異常。
Cause: java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x91\x87\xE7\x9A…’ for column ‘content’ at row 1
環(huán)境
mysql-connector-java-5.1.46 mysql 5.7.27
原因:字符集編碼選擇
我們新建mysql數(shù)據(jù)庫(kù)的時(shí)候,需要指定數(shù)據(jù)庫(kù)的字符集,一般我們都是選擇utf8這個(gè)字符集。而如果我們仔細(xì)觀察的話,其實(shí)我們會(huì)發(fā)現(xiàn)還有一種utf8mb4字符集。那么這兩者有什么關(guān)聯(lián)呢。
utf8mb4 的出現(xiàn)
utf8 是 Mysql 中的一種字符集,只支持最長(zhǎng) 三個(gè)字節(jié) 的 UTF-8字符,也就是 Unicode 中的基本多文本平面。
- utf8 是 MySQL 中的一種字符集,最早支持的 UTF-8 編碼。
- 它只能存儲(chǔ)最長(zhǎng)三個(gè)字節(jié)的 UTF-8 字符,也就是 Unicode 中的基本多文本平面(BMP)中的字符。
- 原始的 utf8 實(shí)現(xiàn)并沒(méi)有涵蓋所有 Unicode 字符,僅支持 BMP 中的字符,大約占所有 Unicode 字符的 90%。
- 在 MySQL 5.7 及更早版本中,utf8 是默認(rèn)字符集。
MySQL在5.5.3之后增加了這個(gè)utf8mb4的編碼,mb4就是most bytes 4的意思,專(zhuān)門(mén)用來(lái)兼容四字節(jié)的unicode。
好在utf8mb4是utf8的超集,除了將編碼改為utf8mb4外不需要做其他轉(zhuǎn)換。
當(dāng)然,為了節(jié)省空間,一般情況下使用utf8也就夠了。
可以簡(jiǎn)單的理解 utf8mb4 是目前最大的一個(gè)字符編碼,支持任意文字。
Mysql 中的 utf8 為什么只支持持最長(zhǎng)三個(gè)字節(jié)的 UTF-8字符呢?
- 我想了一下,可能是因?yàn)?Mysql 剛開(kāi)始開(kāi)發(fā)那會(huì),Unicode 還沒(méi)有輔助平面這一說(shuō)呢。
- 那時(shí)候,Unicode 委員會(huì)還做著 “65535 個(gè)字符足夠全世界用了”的美夢(mèng)。
- Mysql 中的字符串長(zhǎng)度算的是字符數(shù)而非字節(jié)數(shù),對(duì)于 CHAR 數(shù)據(jù)類(lèi)型來(lái)說(shuō),需要為字符串保留足夠的長(zhǎng)。
- 當(dāng)使用 utf8 字符集時(shí),需要保留的長(zhǎng)度就是 utf8 最長(zhǎng)字符長(zhǎng)度乘以字符串長(zhǎng)度,所以這里理所當(dāng)然的限制了 utf8 最大長(zhǎng)度為 3,比如 CHAR(100) Mysql 會(huì)保留 300字節(jié)長(zhǎng)度。
- 至于后續(xù)的版本為什么不對(duì) 4 字節(jié)長(zhǎng)度的 UTF-8 字符提供支持,我想一個(gè)是為了向后兼容性的考慮,還有就是基本多文種平面之外的字符確實(shí)很少用到。
要在 Mysql 中保存 4 字節(jié)長(zhǎng)度的 UTF-8 字符,需要使用 utf8mb4 字符集,但只有 5.5.3 版本以后的才支持。
我覺(jué)得,為了獲取更好的兼容性,應(yīng)該總是使用 utf8mb4 而非 utf8. 對(duì)于 CHAR 類(lèi)型數(shù)據(jù),utf8mb4 會(huì)多消耗一些空間,根據(jù) Mysql 官方建議,使用 VARCHAR 替代 CHAR。
解決方案
修改 Mysql 數(shù)據(jù)中數(shù)據(jù)表的編碼格式,設(shè)置成 utf8mb4
1. 修改編碼方式
- 修改單個(gè)字段編碼方式
alter table <表名> modify column <字段名> <字段類(lèi)型> character set utf8mb4 collate utf8mb4_unicode_ci;
utf8mb4_unicode_ci 是排序方式
- 修改表編碼方式
ALTER TABLE <表名> CONVERT TO CHARACTER SET utf8mb4 COLLATE UTF8MB4_UNICODE_CI;
或者直接通過(guò)cavicat or sqlyog 等連接工具修改編碼方式表。有時(shí)候修改沒(méi)有效果,還是需要命令行修改。
2. 更改mysql 參數(shù)
mysql 字符集參數(shù)查看
SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%'

character_set_client:客戶端字符集,用于指定從客戶端發(fā)送到服務(wù)器的字符集。character_set_connection:連接字符集,用于指定客戶端與服務(wù)器之間的連接字符集。character_set_database:數(shù)據(jù)庫(kù)字符集,用于指定創(chuàng)建新數(shù)據(jù)庫(kù)時(shí)的默認(rèn)字符集。character_set_results:結(jié)果字符集,用于指定從服務(wù)器返回給客戶端的結(jié)果字符集。character_set_server:服務(wù)器字符集,用于指定服務(wù)器的默認(rèn)字符集。collation_server:服務(wù)器校對(duì)規(guī)則,用于指定服務(wù)器的默認(rèn)校對(duì)規(guī)則。collation_database:數(shù)據(jù)庫(kù)校對(duì)規(guī)則,用于指定創(chuàng)建新數(shù)據(jù)庫(kù)時(shí)的默認(rèn)校對(duì)規(guī)則。collation_connection:連接校對(duì)規(guī)則,用于指定客戶端與服務(wù)器之間的連接校對(duì)規(guī)則。
SET GLOBAL character_set_client = utf8mb4; SET GLOBAL character_set_connection = utf8mb4; SET GLOBAL character_set_database = utf8mb4; SET GLOBAL character_set_results = utf8mb4; SET GLOBAL character_set_server = utf8mb4; SET GLOBAL collation_server = utf8mb4_unicode_ci; SET GLOBAL collation_database = utf8mb4_unicode_ci; SET GLOBAL collation_connection = utf8mb4_unicode_ci;
需要 重啟數(shù)據(jù)庫(kù) 生效?。?!
- 需要注意的是,修改字符集可能會(huì)涉及到數(shù)據(jù)轉(zhuǎn)換和重新排序操作。在執(zhí)行這些操作之前,請(qǐng)務(wù)必備份您的數(shù)據(jù)庫(kù),以防數(shù)據(jù)丟失或不可逆的更改發(fā)生。
- 只改這個(gè)兩個(gè)也能成功。
character_set_server,collation_server
注意
在解決這個(gè)問(wèn)題的過(guò)程中,還有一些其他的冗余操作,屬于加上也能正常入口特殊字段,但不加也行。如何問(wèn)題沒(méi)有解決的話,不妨一試。
1.數(shù)據(jù)庫(kù)鏈接接增加 &character_set_server=utf8mb4
Connector/J 5.1.47 及以上版本:
- 指定 characterEncoding 參數(shù)為 UTF8/UTF-8 即可, 新版本直接映射到 utf8mb4 編碼;
- 如果 connectionCollation 指定的排序規(guī)則不是 utf8mb4 相關(guān)的, 則 characterEncoding 參數(shù)會(huì)重寫(xiě)為排序規(guī)則對(duì)應(yīng)的編碼;
Connector/J 5.1.47 以下版本:
- 設(shè)置 MySQL 參數(shù)變量 character_set_server=utf8mb4;
- 指定 characterEncoding 參數(shù)為 UTF8/UTF-8, jdbc 程序會(huì)進(jìn)行探測(cè)是否使用 utf8mb4;
2.在 application.yaml 中添加下面屬性
initConnectionSqls=[ "SET NAMES utf8mb4"]
獲取上面的值并設(shè)置給數(shù)據(jù)源
dataSource.setConnectionInitSqls(sqlLists);
- connectionInitSqls 是一個(gè)用于配置數(shù)據(jù)庫(kù)連接池的屬性,它允許您指定在每個(gè)數(shù)據(jù)庫(kù)連接建立時(shí)要執(zhí)行的初始化 SQL 語(yǔ)句。
- 這些 SQL 語(yǔ)句可以用于在連接建立后執(zhí)行一些特定的操作,例如設(shè)置會(huì)話變量、執(zhí)行特定的查詢(xún)或配置連接的特性。
- 在許多數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)中,包括一些開(kāi)源的連接池庫(kù)和應(yīng)用服務(wù)器,都支持 connectionInitSqls 屬性來(lái)定義連接初始化 SQL。
- 通過(guò)配置這個(gè)屬性,您可以確保每個(gè)連接在使用之前都會(huì)執(zhí)行指定的 SQL 語(yǔ)句。
3.使用最新的 MySQL 連接器。
mysql:mysql-connector-java:8.0.27 jdbc:mysql://192.168.10.10:3306/db_name?characterEncoding=utf8
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- java.sql.SQLException:?connection?holder?is?null錯(cuò)誤解決辦法
- Java中java.sql.SQLException異常的正確解決方法(親測(cè)有效!)
- java報(bào)錯(cuò)Cause: java.sql.SQLException問(wèn)題解決
- java.sql.SQLException問(wèn)題解決以及注意事項(xiàng)
- java.sql.SQLException: 內(nèi)部錯(cuò)誤: Unable to construct a Datum from the specified input
- java.sql.SQLException異常原因排查與解決
相關(guān)文章
MySQL?排序規(guī)則Collation實(shí)例詳解
本文將從基礎(chǔ)概念出發(fā),詳解排序規(guī)則的作用、與字符集的關(guān)系、查看與配置方法,并通過(guò)實(shí)際案例說(shuō)明其對(duì)查詢(xún)結(jié)果的影響,幫助開(kāi)發(fā)者精準(zhǔn)控制數(shù)據(jù)匹配行為,感興趣的朋友一起看看吧2025-07-07
mysql多行子查詢(xún)實(shí)戰(zhàn)案例(只包含不相關(guān)子查詢(xún))
在MySQL中多行子查詢(xún)(也稱(chēng)為 IN 子查詢(xún))是指子查詢(xún)返回多行數(shù)據(jù),并且這些數(shù)據(jù)用于主查詢(xún)中的某個(gè)條件判斷,這篇文章主要介紹了mysql多行子查詢(xún)(只包含不相關(guān)子查詢(xún))的相關(guān)資料,需要的朋友可以參考下2024-10-10
常見(jiàn)的十種SQL語(yǔ)句性能優(yōu)化策略詳解
這篇文章主要介紹了常見(jiàn)的十種SQL語(yǔ)句性能優(yōu)化策略詳解,SQL語(yǔ)句性能優(yōu)化是提高數(shù)據(jù)庫(kù)查詢(xún)效率的關(guān)鍵步驟,可以減少查詢(xún)時(shí)間,提高系統(tǒng)響應(yīng)速度,本文將介紹一些常見(jiàn)的SQL語(yǔ)句性能優(yōu)化技巧,包括索引的使用、合理的查詢(xún)條件、避免全表掃描等,需要的朋友可以參考下2023-10-10
mysql回表查詢(xún)是什么,回表查詢(xún)的使用
這篇文章主要介紹了mysql回表查詢(xún)是什么,回表查詢(xún)的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2022-11-11
淺談MyISAM 和 InnoDB 的區(qū)別與優(yōu)化
InnoDB和MyISAM是在使用MySQL最常用的兩個(gè)表類(lèi)型,各有優(yōu)缺點(diǎn),視具體應(yīng)用而定。下面我們就來(lái)具體探討下吧2015-07-07
MySQL8.0就地升級(jí)到MySQL8.4.0的方法
本文主要介紹了MySQL8.0就地升級(jí)到MySQL8.4.0的方法,文中通過(guò)代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06
MariaDB 新版本實(shí)力逆襲不僅僅是 MySQL 替代品
MariaDB是MySQL源代碼的一個(gè)分支,主要由開(kāi)源社區(qū)在維護(hù),采用GPL授權(quán)許可。MariaDB 10.0和MySQL 5.6的不同之處有那些,MariaDB和Percona有什么不同呢?下面通過(guò)本文詳細(xì)了解下吧2016-12-12

