首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JDBC-ODBC Bridge查询在包含重音字符时无法访问

JDBC-ODBC Bridge查询在包含重音字符时无法访问
EN

Stack Overflow用户
提问于 2014-01-10 05:53:50
回答 2查看 1K关注 0票数 1

我通过JDBC-ODBC Bridge将查询从Java发送到Access数据库,如下所示:

代码语言:javascript
复制
"SELECT * FROM localities WHERE locName='" + cityName + "'"

当cityName是没有重音字符的普通字符串时,结果集是正确的。但是当cityName恰好是像LEÓNSAHAGÚN这样带有重音字符的东西时,我就得不到任何结果。在这些情况下,查询似乎失败了。同样的查询在MS Access中运行时也能正常工作,我也尝试了Ms Data Acces SKD,这些查询工作得很好。

它们只有在通过JDBC-ODBC桥时才会失败。据我所知,Java使用UTF-8作为字符串,Access也使用UTF-8。而且它们都使用Unicode。有没有人知道这个问题的解决方案?

EN

回答 2

Stack Overflow用户

发布于 2014-01-10 20:27:34

听起来您的Java源文件被编码为UTF-8,因此当cityName字符串包含LEÓN时,它被编码为

代码语言:javascript
复制
L  E  Ó     N
-- -- ----- --
4C 45 C3 93 4E

这不是Access存储值的方式。Access确实将字符存储为Unicode,但它不使用UTF-8编码。它使用UTF-16LE编码的变体,其中码位在U+00FF及以下的字符存储在单个字节中,码位在U+00FF以上的字符存储为Null (0x0)值,后跟UTF-16LE字节对。在本例中,Ó为U+00D3,它位于U+00FF之下,因此Access将字符串的所有四个字符存储为单个字节:

代码语言:javascript
复制
L  E  Ó  N
-- -- -- --
4C 45 D3 4E

最终结果是,Access数据库中字符串的编码与ISO 8859-1字符集的编码相同。

这可以通过使用JDBC-ODBC Bridge的以下Java代码来确认。当Java源文件被编码为UTF-8时,它无法找到所需的记录,但当Java源文件在Eclipse中被编码为cp1252时,它可以工作:

代码语言:javascript
复制
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桥和Access ODBC驱动程序之间长期存在的互操作性问题,并且无法修复。(更多详细信息here。)

在这种情况下,您可能需要考虑使用UCanAccess,它是用于访问的纯Java JDBC驱动程序。使用带有UTF8编码的源文件的UCanAccess的相应代码如下

代码语言:javascript
复制
// 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):

代码语言:javascript
复制
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();
        }
    }

}
票数 2
EN

Stack Overflow用户

发布于 2014-01-10 17:38:07

尝试使用PreparedStatement。

我刚刚用Jython2.5测试了MS Access Northwind数据库,它使用JDBC-ODBC桥:

代码语言:javascript
复制
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()

在您的代码中,它将如下所示:

代码语言:javascript
复制
pstm = db.prepareStatement("SELECT * FROM localities WHERE locName=?");
pstm.setString(1, locName);
rs = pstm.executeQuery();
...
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21031995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档