掉坑回顧:
最近在工作中遇到一個BUG,用於記錄客戶昵稱的數據表,在插入帶有表情的字符時候報錯.使用的存儲引擎是INNODB,當我查看數據庫字段的時候確實是設置的utf8,我傳入的字符也是utf8的編碼集,這有什么錯?直到我深入了解才發自己使用的姿勢並不對,mysql數據庫中的"utf8"並不是真正的utf8編碼,關於這個問題mysql官方一直未能修復,取而代之的推出了utf8mb4,這一點讓我記憶猶新,切記mysql中不要再使用utf8編碼!
1.BUG重現
這里我做了一個簡單的試驗,來驗證utf8在mysql中存在的問題:
建立數據表:
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`nickname` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '昵稱',
`sex` varchar(255) DEFAULT NULL COMMENT '性別',
`age` int(10) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='測試utf8問題重現'
這里我們直接指定了nickname字段的字符編碼為utf8,然后我向里面插入一條普通數據,使用mybatis的插入數據庫語句如下:
INSERT INTO `user` ( `nickname`, `sex`, `age`) VALUES ( '張三', '男', '18');
的確是像我們平時操作一樣插入成功了,似乎沒有什么問題,但這里我們再測試一下昵稱中帶有表情符(emoji)的數據嘗試一下:
張三 An 😀awesome 😃string 😄with a few 😉emojis!
Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x80aw...' for column 'nickname' at row 1
這個時候報的錯誤就很明顯是指的這個表情符無法存入該字段,那為什么emoji無法存入utf8編碼的字段呢,這又是怎么回事呢?
2.Mysql遺留問題
這個問題的症結在於,Mysql的"utf8"並不是真正的UTF-8.
“utf8”只支持每個字符三個字節,而真正的 UTF-8 是每個字符最多四字節,MySQL 一直沒有修復這個 bug,他們在 2010 年發布了一個叫作“utf8mb4”的字符集,繞過了這個問題,但為什么沒有修復"utf8"問題?具體原因不詳.
簡單歸納綜合如下:
MySQL 的“utf8mb4”是真正的“UTF-8”,MySQL 的“utf8”是一種“專屬的編碼”,它能夠編碼的 Unicode 字符其實不多,所以在使用mysql的時候還是用"utf8mb4"的編碼集恰當!

