1. 程式人生 > >mysql處理Latin 中文繁體字亂碼解決方案

mysql處理Latin 中文繁體字亂碼解決方案

問題描述:

1. 對於一些中文繁體字元select出來出現亂碼,出問題的繁體字如:燈、龍等

環境描述:

資料庫編碼:

+--------------------------+----------------------------------------+

| Variable_name            | Value                                  |

+--------------------------+----------------------------------------+

| auto_increment_offset    | 1                                      |

| character_set_client     | latin1                                 |

| character_set_connection | latin1                                 |

| character_set_database   | latin1                                 |

| character_set_filesystem | binary                                 |

| character_set_results    | latin1                                 |

| character_set_server     | latin1                                 |

| character_set_system     | utf8                                   |

| character_sets_dir       | D:/Program Files/mysql/share/charsets/ |

+--------------------------+----------------------------------------+

資料庫表編碼:也同意使用latin1編碼方式

由於資料庫由DBA負責,並且庫結構為了保持一致(我們使用備份庫),從而不能修改資料庫編碼

問題排查:

1.mysql 的jdbc驅動原始碼拷貝下來DEBUG,最終發現了問題根源在驅動中CharSetMapping.class該類中的getJavaEncodingForMysqlEncoding(String mysqlEncoding,Connection conn)方法,該方法原始碼如下:

[java] view plaincopyprint?
  1. public final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding,  
  2.             Connection conn) throws SQLException {  
  3.         if (conn != null && conn.versionMeetsMinimum(410) &&   
  4.                 "latin1".equalsIgnoreCase(mysqlEncoding)) {  
  5.             return "Cp1252";  
  6.         }  
  7.         return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding);  
  8.     }  
 

這裡Latin1編碼就是iso-8859-1編碼。問題就出在這裡,mysql驅動對Latin1編碼做了特殊處理,轉為cp1252,但cp1252依然屬於Latin1系編碼,故顯示中文依然會存在亂碼,故需要在GBKstring中轉化cp1252.

這麼做了以後,發現我看到的中文都不再亂碼OK,包括一些繁體字和火星文,大功告成了。

過了一天,我們測試給我反饋結果,說一些繁體字依然存在亂碼,比如“燈、龍”等,在頁面上顯示“?”,究竟哪兒出了問題?繼續DEBUG,

發現普通漢字從Latin1轉碼為cp1252後的byte array中的資料中,用兩個位元組表示一個漢字時,能夠在GBK編碼對映表中找到byte array對應的2位元組資料,而“燈、龍”兩個繁體字轉cp1252後,其對應的byte array中的2位元組資料無法再GBK編碼中找到(既GBK中無法找到該2位元組資料對應的漢子),從而出現“?”。

故問題應該就出現在這裡,既從latin1->cp1252->gbk這樣一個過程會出現以下編碼資料丟失。從而解決方案也是很明顯的:

既:去掉中間轉cp1252的步驟,直接將Latin1 轉gbk,同時gbkString中不處理,將上面程式碼修改為:

[java] view plaincopyprint?
  1. public final static String getJavaEncodingForMysqlEncoding(String mysqlEncoding,  
  2.             Connection conn) throws SQLException {  
  3.         if (conn != null && conn.versionMeetsMinimum(410) &&   
  4.                 "latin1".equalsIgnoreCase(mysqlEncoding)) {  
  5.             return "gbk";  
  6.         }  
  7.         return (String) MYSQL_TO_JAVA_CHARSET_MAP.get(mysqlEncoding);  
  8.     }  

出處:http://blog.csdn.net/workwithwebis3w/article/details/5875314

個人理解:可以將資料庫裡查出來的資料強轉new String(str.getBytes("GBK"),"cp1252");

儲存時直接強轉: new String(str.getBytes("cp1252"),"GBK");