MySQL Server 與中文
The materials presented in this web page is provided as is and is used solely for educational purpose. Use at your own risks.Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
請勿轉貼
看其他教材
絕大多數的 Java 程式開發人員在使用 MySQL 之後,都會發現 Java 程式 在存取中文資料的時候很容易出現亂碼,但是英文的資料卻不會。這個問題 之所以存在的主要原因之一就是資料的編碼;身為一個程式開發人員,如果你的 程式(不限定於 Java)發生了中文亂碼的情形,你應該問問自己以下的問題: 資料庫儲存中文資料時,是以什麼 樣的編碼方式儲存,大五碼嗎?資料庫跟客戶端程式互相傳遞資料的時候, 它們又是以什麼樣的編碼在傳遞,大五碼嗎?你的應用程式中的中文資料 是以什麼方式編碼,大五碼嗎?在了解了這些編碼的情形之後,絕大部分的 問題應該可以迎刃而解。
如果世界上存在一種標準,要求所有上述的情形都是以大五碼的方式進行, 那麼這篇文章就不需要存在了。可是,對於那些不使用大五碼的國家呢? 他們該怎麼辦?所以,為了設計上的彈性,大多數的系統都會使用某一種 特定的預設編碼;如果你需要特定的編碼,你就必須仔細看完安裝手冊, 然後依據該手冊的要求進行安裝。問題是大多數人是不看手冊的(你是在 說我嗎?你可以再靠近一點 ^_^),或者手冊編寫的不好。
所以,這篇文章就是要談一談 MySQL Server 跟中文使用上的一些細節。 如果你是第一次安裝 MySQL Server 的人,請直接依據 在 Windows 安裝 Noinstall Zip Archive 版的 MySQL中,my.ini 的設定即可。 (如果你使用的是 Linux 的話,你需要依據環境的需求來更改設定檔;以 Debian 上利用 apt-get 的方式安裝 MySQL 5.0.x 版的話,你需要 修改 /etc/mysql/my.cnf 的內容) 如果你已經在 MySQL Server 中建立了一些資料,我們建議把這些資料 (也就是表格以及資料庫)刪除掉,然後依據我們的設定修改後,重新啟動 MySQL。如果你已經有很多資料,那麼請仔細看一下以下的說明,然後自己找出 一套適當的方法(不論是適當的轉碼還是"備份後還原")。"備份後還原"的方式 我還沒試過,或許幾年後我的伺服器需要升級的時候,我再來看看這些步驟該如何進行, 如果精神好的話,或許再寫一篇文章也說不定。
雖然 MySQL Server 從 4.1.16 以及 5.0.16 以後的版本就開始支援中文的大五碼, 但是在標準安裝的過程中,它使用的預設編碼是 latin1。你可以使用 mysql 執行檔來檢查;如果輸入 status;,你會看到如下的畫面:
依據 Wikipedia 的說明,latin1 其實就是 ISO-8859-1 的編碼;也就是說, 如果你是依據 MySQL 預設的編碼來儲存中文資料,在你的程式送出 Big5 的資料之前, 請先以 ISO-8859-1 的方式先行轉碼,然後中文資料會以 ISO-8859-1 的編碼方式 儲存在資料庫中。之後,如果你需要將中文資料擷取出來的話,那麼你可以要求 顯示的編碼方式為 ISO-8859-1 或者(如果顯示的編碼方式為 Big5)將 ISO-8859-1 的資料轉碼成 Big5。
依據這個原則所寫出來的程式如以下的完整程式碼;在此我們把所謂的轉碼方式 說明一下。在查詢的時候,我們依據 rs.getString(i) 的方式把資料 從資料庫中以字串的方式取出來;由於該字串是以 ISO-8859-1 的方式編碼, 我們可以利用 getBytes("ISO-8859-1") 的方式把字串的內容一個 byte 一個 byte 的以 ISO-8859-1 編碼方式取出並形成一個 byte 陣列,然後以 String 的建構元,請它依據 Big5 的編碼方式形成字串,因此資料轉換的方式 如下:
System.out.print(new String(rs.getString(i).getBytes("ISO-8859-1"), "Big5"));
executeUpdate(new String(SQL.getBytes("Big5"), "ISO-8859-1"));
import java.sql.*; public class NewJDBC { static String classname = "com.mysql.jdbc.Driver"; static String jdbcURL = "jdbc:mysql://localhost/eric"; static String UID = "jlu"; static String PWD = "newpasswd"; static Connection conn = null; public static void main( String argv[] ) { // initialize query string if(argv.length != 1) { System.out.println("Usage: java NewJDBC "); System.out.println(" ex. java NewJDBC Product"); System.exit(2); } String aQuery = "select * from " + argv[0]; String iSQL = "insert into " + argv[0] + " values(5,'鍵盤',14.5,2)"; String uSQL = "update " + argv[0] + " set Name='無線鍵盤' where ID=5"; String dSQL = "delete from " + argv[0] + " where ID=5"; try { // load the JDBC-ODBC bridge driver Class.forName(classname).newInstance(); // connect to Database conn = DriverManager.getConnection(jdbcURL,UID,PWD); // Display current content System.out.println("Display current content"); ShowResults(aQuery); // Insert a new record System.out.println("\nInserting a new record ....."); InsertNew(iSQL); ShowResults(aQuery); // Update record System.out.println("\nUpdateing a record ....."); UpdateNew(uSQL); ShowResults(aQuery); // Delete record System.out.println("\nDeleting a record ....."); DeleteNew(dSQL); ShowResults(aQuery); conn.close(); } catch (Exception sqle) { System.out.println(sqle); System.exit(1); } } private static void DeleteNew(String dSQL) { try { Statement aStatement = conn.createStatement(); aStatement.executeUpdate(dSQL); } catch (Exception e) { System.out.println("Delete Error: " + e); System.exit(1); } } private static void UpdateNew(String uSQL) { try { Statement aStatement = conn.createStatement(); // ISO-8859-1 其實就是 latin1 的編碼 // 以下的目的是要把 BIG5 的字串轉成 byte array 然後再轉成符合 // 目前的 latin1 的編碼 aStatement.executeUpdate(new String(uSQL.getBytes("BIG5"), "ISO-8859-1")); } catch (Exception e) { System.out.println("Update Error: " + e); System.exit(1); } } private static void InsertNew(String iSQL) { try { Statement aStatement = conn.createStatement(); // 與 UpdateNew 一樣 aStatement.executeUpdate(new String(iSQL.getBytes("BIG5"), "ISO-8859-1")); } catch (Exception e) { System.out.println("Insert Error: " + e); System.exit(1); } } private static void ShowResults(String aQuery) { try { // Construct a SQL statement and submit it Statement aStatement = conn.createStatement(); ResultSet rs = aStatement.executeQuery(aQuery); // Get info about the query results ResultSetMetaData rsmeta = rs.getMetaData(); int cols = rsmeta.getColumnCount(); // Display column headers for(int i=1; i<=cols; i++) { if(i > 1) System.out.print("\t"); System.out.print(rsmeta.getColumnLabel(i)); } System.out.print("\n"); // Display query results. while(rs.next()) { for(int i=1; i<=cols; i++) { if (i > 1) System.out.print("\t"); // 由於資料庫的預設編碼為 latin1,所以傳出的也是 latin1, // 因此我們需要把所得到的字串從 latin1 轉成我們可以看得到 // 的 BIG5 System.out.print(new String(rs.getString(i).getBytes("ISO-8859-1"), "BIG5")); } System.out.print("\n"); } // Clean up rs.close(); aStatement.close(); } // a better exception handling can be used here. catch (Exception e) { System.out.println("Exception Occurs."); } } }
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
沒有留言:
張貼留言