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
沒有留言:
張貼留言