java 與 mysql 中文問題的處理
來源:互聯網
上載者:User
mysql|問題|中文 問題:用 jdbc 插入、讀取資料庫種文字串亂碼。
首先,mysql 資料庫中的東西都是二進位存放的,支援任何資料,當然包括中文。你到命令列下
insert into testtable values ( '中文' );
select * from testtable;
全都顯示正常。
但是,雖然存取中文沒問題,但排序、匹配的時候有問題。所以如果你的資料庫裡有中文的話,記得在設定檔中,如 c:winntmy.ini 中的 [mysqld] 裡添加一行:
default-character-set=gbk
然後重啟 mysql server 。 注意 gbk 要小寫,不然 mysqld 啟動不了。
其次,資料庫沒問題,下面看看 java 程式。在程式裡很無聊地加一句調試語句:
out.println("中文");
也顯示正常,說明整個 java 環境沒問題。
所以,當然是聯絡 java 和 mysql 的部分,mysql jdbc driver 出問題了。
分析一下,java 內部使用 unicode ,而 mysql 預設使用 iso-8xxx(忘了),所以 jdbc driver 把查詢字串傳給 mysql server 時,會做 unicode->iso-8xxx 的轉換,從 mysql server 接受結果時,會做 iso-8xxx->unicode 的轉換。(在螢幕上顯示結果時會 unicode->GBK,不過不關這裡的事。)
這就有問題了,我在命令列下插入資料庫的中文字串是 GBK (這是簡體中文 windows 的預設),所以 jdbc driver 接受查詢結果時,應該做 GBK->unicode 的轉換才對。
驗證一下,對從資料庫中讀出的中文字串 s ,
new String( s.getByte("iso-8xxx"), "gbk" )
將 s 先做一個 unicode->iso-8xxx 轉換成它存放在資料庫中的原始模樣。我們知道它是 gbk ,所以手工來 gbk->unicode ,這樣 java 程式就顯式正常了。
類似,寫入資料庫的時候,我們期待 jdbc driver 會把 unicode->gbk ,結果卻是 unicode->iso-8xxx ,當然是亂碼了。
有很多文章,就到此為止,並告訴我們:要解決中文問題,自己手工轉碼吧。
這實在是不負責任。如果每一個字串都要手工轉碼,說明程式設計出了問題。
想一想,寫 mysql jdbc driver 的傢伙會連轉碼都不知道?
所以我看看 connector-j-3.0.7 裡面的 readme, 找到一個解決方案:
connection = DriverManager.getConnection( "jdbc:mysql://localhost/test?user=root&password=&useUnicode=true&characterEncoding=GBK" );
這是告訴 jdbc driver 強制按指定參數轉碼
其實還是有問題。如果 mysql server 一定得用 iso-8xxx ,那就只有用上一個辦法了。但我記得我的 mysql 是 gbk ,不是都改過 my.ini 了嗎? jdbc driver 怎麼都不自動探測 mysql server 的字元集呢?
這個時候就看到開放源碼的好處了 :-) connector-j-3.0.7 源碼中確實有代碼讀取 mysql server 的資訊,包括字元集。從注釋中知道,
作者為 unicode 轉換到單一位元組字元集寫了自己的轉換函式,並號稱比 jvm 的快百分之多少多少。所以代碼中有一段,判段資料庫如果使用的是單位元組就調用自己的轉換函式。但這段代碼後面就忘了把多位元組字元集交給 jvm 去轉換了,所以變成了預設的 iso-8xxx 轉換。
我的修改方式: commysqljdbcConnecter.java 這個檔案的 1969 行,
this.doUnicode = true; // force the issue
將之上移四行到 1964 行,放在下面這一行的前面:
try {
用這份代碼重新編出來的 jdbc driver ,你的 java 訪問資料庫的程式不用做任何修改就可以正確讀寫中文了,不過要記得 mysql server 要 default-character-set=gbk
我使用它測試了幾個小程式,中文都顯示正常,而且都沒死機、異常。呵呵,自我感覺很好。