2014-01-09 48 views
1

我送通過JDBC-ODBC橋查詢從Java Access數據庫中,這樣的失敗:JDBC-ODBC橋查詢訪問時,他們已重音符號

"SELECT * FROM localities WHERE locName='" + cityName + "'" 

當的cityName是正常的沒有重音字符的字符串,結果集是正確的。 但是當cityName恰好是LEÓN,SAHAGÚN這樣的字符時,它們會帶有重音字符,那麼我就沒有結果。在這些情況下,查詢似乎失敗。 當在MS Access中運行相同的查詢工作正常時,我也嘗試使用Ms Data Acces SKD並且這些查詢完美地工作。

它們只在通過JDBC-ODBC Bridge時失敗。 據我所知,Java使用UTF-8作爲字符串,Access也是如此。他們都使用Unicode。 有誰知道這個問題的任何解決方案?

+0

那麼,你得到這個整理出來? –

回答

0

嘗試使用PreparedStatement。

我剛纔測試了使用Jython 2.5的MS Access Northwind數據庫,它使用JDBC-ODBC橋:

c = db.createStatement() 
TRADH = u'Tradi\xe7\u0103o Hipermercados' 
pstm = db.prepareStatement("SELECT CustomerID, CompanyName FROM customers WHERE CompanyName=?") 
pstm.setString(1, TRADH) 
rs = pstm.executeQuery() 
while (rs.next()): 
    try: 
     s1 = rs.getString(1) 
     s2 = rs.getString(2) 
     print('[%s] [%s]' % (s1, s2)) 
    except UnicodeEncodeError: 
     print('[%s] [%s] !!!' % (s1, repr(s2))) 
c.close() 

在你的代碼,它看起來像:

pstm = db.prepareStatement("SELECT * FROM localities WHERE locName=?"); 
pstm.setString(1, locName); 
rs = pstm.executeQuery(); 
... 
2

這聽起來像你的Java源文件編碼爲UTF-8,所以當cityName字符串包含LEÓN時,它被編碼爲

L E Ó  N 
-- -- ----- -- 
4C 45 C3 93 4E 

這不是Access如何存儲該值。 Access將字符存儲爲Unicode,但不使用UTF-8編碼。它使用UTF-16LE編碼的變體,其中代碼點U + 00FF及以下的字符存儲在單個字節中,代碼點大於U + 00FF的字符存儲爲空(0x0)值,後跟UTF-16LE字節對。在這種情況下Ó是U + 00D3,低於U + 00FF,因此訪問存儲的字符串作爲單字節的所有四個字符:

​​

的淨效應是,該字符串在訪問數據庫中的編碼與ISO 8859-1字符集相同。

這可以通過使用JDBC-ODBC Bridge的以下Java代碼進行確認。它未能找到當Java源文件編碼爲UTF-8所需的記錄,但是當Java源文件在Eclipse中編碼爲cp1252它的工作原理:

import java.sql.*; 

public class accentTestMain { 

    public static void main(String[] args) { 
     String connectionString = 
       "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};" + 
       "DBQ=C:\\__tmp\\test\\accented.accdb;"; 
     try { 
      Connection con = DriverManager.getConnection(connectionString); 
      PreparedStatement stmt = con.prepareStatement("SELECT * FROM localities WHERE locName=?"); 
      String cityName = "LEÓN"; 
      stmt.setString(1, cityName); 
      stmt.execute(); 
      ResultSet rs = stmt.getResultSet(); 
      if (rs.next()) { 
       System.out.println(String.format("Record found, ID=%d", rs.getInt("ID"))); 
      } 
      else { 
       System.out.print("Record not found."); 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

如果你可以用僅支持重音字符做用cp1252字符集表示,那麼您應該可以簡單地使用cp1252作爲Java源文件的編碼設置。

另一方面,如果您確實需要使用Access數據庫完全支持Unicode字符,那麼JDBC-ODBC Bridge將不會爲您完成工作。這是JDBC-ODBC Bridge和Access ODBC驅動程序之間長期存在的互操作性問題,它不會被修復。 (更多詳細信息here。)

在這種情況下,您可能需要考慮使用UCanAccess,它是Access的純Java JDBC驅動程序。使用UCanAccess用UTF-8編碼的源文件中的對應的代碼將是

// assumes... 
//  import java.sql.*; 
Connection conn=DriverManager.getConnection(
     "jdbc:ucanaccess://C:/__tmp/test/accented.accdb"); 
PreparedStatement ps = conn.prepareStatement(
     "SELECT ID FROM localities WHERE locName=?"); 
ps.setString(1, "LEÓN"); 
ResultSet rs = ps.executeQuery(); 
if (rs.next()) { 
    System.out.println(String.format(
      "Record found, ID=%d", 
      rs.getInt("ID"))); 
} 
else { 
    System.out.println("Record not found."); 
} 

有關詳細信息有關使用UCanAccess,請參閱相關問題here

另一種解決方案是使用Jackcess操縱Access數據庫像這樣(再次,Java源文件編碼爲UTF-8):

import java.io.File; 
import java.io.IOException; 
import com.healthmarketscience.jackcess.*; 

public class accentTestMain { 

    public static void main(String[] args) { 
     Database db; 
     try { 
      db = DatabaseBuilder.open(new File("C:\\__tmp\\test\\accented.accdb")); 
      try { 
       Table tbl = db.getTable("localities"); 
       Cursor crsr = CursorBuilder.createCursor(tbl.getIndex("locName")); 
       if (crsr.findFirstRow(tbl.getColumn("locName"), "LEÓN")) { 
        System.out.println(String.format("Record found, ID=%d", crsr.getCurrentRowValue(tbl.getColumn("ID")))); 
       } 
       else { 
        System.out.println("Record not found."); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       db.close(); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

}