1. 程式人生 > >MySql 中文寫入資料庫亂碼及Incorrect string value: '\xF0\x9F...' for column 'XXX' at row 1解決

MySql 中文寫入資料庫亂碼及Incorrect string value: '\xF0\x9F...' for column 'XXX' at row 1解決

一、中文寫入亂碼問題

我輸入的中文編碼是urf8的,建的庫是urf8的,但是插入MySQL總是亂碼,一堆"???????????????????????"。可以使用以下的方式試試決解:
原url地址是

jdbc:mysql://localhost:3306/資料庫名

改為

jdbc:mysql://localhost:3306/資料庫名?useUnicode=true&characterEncoding=UTF-8

就OK了。

二、Incorrect string value: '\xF0\x9F...' for column 'XXX' at row 1

做有關微信公眾賬號的專案時,報Incorrect string value: '\xF0\x9F\x98\x92' for column 'NIKENAME' at row 1,而所有的字元編碼都是utf8,使用的資料庫是mysql,在測試環境用得好好的,部署到線上後(使用的叢集是阿里巴巴的,資料庫伺服器也是使用它們的,mysql伺服器版本是5.5.18),就報這個錯了,並且這個錯,時而出現,時而不出現

Emoji表情字元現在在APP已經廣泛支援了。但是MySQL的UTF8編碼對Emoji字元的支援卻不是那麼好。所以我們經常會遇到這樣的異常:

Java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x8E' for column 'nick' at row 1

原因是Mysql裡UTF8編碼最多隻能支援3個位元組,而Emoji表情字元使用的UTF8編碼,很多都是4個位元組,有些甚至是6個位元組。

解決的方案有兩種:

  1. 使用utf8mb4的mysql編碼來容納這些字元。
  2. 過濾掉這些特殊的表情字元。
方法1:使用utf8mb4的mysql編碼來容納這些字元

注意:要使用utf8mb4型別,首先要保證Mysql版本要不低於 MySQL 5.5.3。

第一步:在mysql的安裝目錄下找到my.ini,作如下修改

[client] 
default-character-set = utf8mb4 
[mysql] 
default-character-set = utf8mb4 
[mysqld] 
character-set-client-handshake = FALSE 
character-set-server = utf8mb4 
collation-server = utf8mb4_unicode_ci 
init_connect='SET NAMES utf8mb4'

修改後重啟Mysql

第二步:將已經建好的表也轉換成utf8mb4

alter table TABLE_NAME convert to character set utf8mb4 collate utf8mb4_bin; 

將TABLE_NAME替換成你的表名。然後就OK了。
網上流傳的一個版本增加了一個步驟,就是以root身份登入Mysql,修改環境變數,將

character_set_client,character_set_connection,character_set_database,character_set_results,character_set_server

都修改成utf8mb4。不過我沒有做這一步,也正常,所以可能是這一步是多餘的。

方法2:過濾掉這些特殊的字元
import org.apache.commons.lang.StringUtils;

public class charUtil {
    /**
     * 替換四個位元組的字元 '\xF0\x9F\x98\x84\xF0\x9F)的解決方案 ��
     */
    public static String removeFourChar(String content) {
        byte[] conbyte = content.getBytes();
        for (int i = 0; i < conbyte.length; i++) {
            if ((conbyte[i] & 0xF8) == 0xF0) {
                for (int j = 0; j < 4; j++) {
                    conbyte[i + j] = 0x30;// 0x30 int=48   字元=0
                }
                i += 3;
            }
        }
        content = new String(conbyte);
        return content.replaceAll("0000", "");
    }

    /**
     * 將emoji表情替換成*
     * @return 過濾後的字串
     * 過濾的方式很簡單,直接使用正則表示式匹配編碼範圍,然後替換就行了。
     */
    public static String filterEmoji(String source) {
        if (StringUtils.isNotBlank(source)) {
            return source.replaceAll("[\\ud800\\udc00-\\udbff\\udfff\\ud800-\\udfff]", "*");
        } else {
            return source;
        }
    }

    public static void main(String[] arg) {
        try {
            System.err.println("測試->將emoji表情替換成*");
            String text = "This is a smiley \uD83C\uDFA6 face\uD860\uDD5D \uD860\uDE07 \uD860\uDEE2 \uD863\uDCCA \uD863\uDCCD \uD863\uDCD2 \uD867\uDD98 ";
            System.out.println(text);
            System.out.println(text.length());
            System.out.println(text.replaceAll("[\\ud83c\\udc00-\\ud83c\\udfff]|[\\ud83d\\udc00-\\ud83d\\udfff]|[\\u2600-\\u27ff]", "*"));
            System.out.println(filterEmoji(text));
            //輸出結果
            //This is a smiley �� face�� �� �� �� �� �� �� 
            //45
            //This is a smiley * face�� �� �� �� �� �� �� 
            //This is a smiley * face* * * * * * * 

            System.err.println("測試->替換四個位元組的字元 '\\xF0\\x9F\\x98\\x84\\xF0\\x9F)的解決方案 ��");
            String title = "ff的范德薩分��������Llfldakf;dsk。f������������daslfjdsa;lfkjdsd'j'l'f'k'd'j'sa'l'k";
            System.out.println(removeFourChar(title));
            //輸出結果:ff的范德薩分Llfldakf;dsk。fdaslfjdsa;lfkjdsd'j'l'f'k'd'j'sa'l'k

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}