ai didi

java - 当 JDBC-ODBC Bridge 对 Access 的查询包含重音字符时会失败

转载 作者:行者123 更新时间:2023-11-30 04:04:43 24 4
gpt4 key购买 nike

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

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

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

它们仅在通过 JDBC-ODBC 桥时才会失败。据我了解,Java 使用 UTF-8 表示字符串,Access 也是如此。而且他们都使用 Unicode。有谁知道这个问题的解决办法吗?

最佳答案

听起来您的 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 的字符存储为 Null (0x0) 值,后跟其 UTF-16LE字节对。在本例中,Ó 为 U+00D3,低于 U+00FF,因此 Access 将字符串的所有四个字符存储为单个字节:

L  E  Ó  N
-- -- -- --
4C 45 D3 4E

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

这可以通过以下使用 JDBC-ODBC 桥的 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();
}
}

}

关于java - 当 JDBC-ODBC Bridge 对 Access 的查询包含重音字符时会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21031995/

24 4 0
文章推荐: c++ - Cin:WAITING 。两个继续 cin.ignore 不起作用
文章推荐: c++ - 如何将圆形数组而不是常规数组传递给 OpenGL 函数?
文章推荐: java - 将 @XmlRootElement 添加到每个 JAXB bean 是否有任何问题?
文章推荐: java - jExcel 获取单元格内容丢失
行者123
个人简介

我是一名优秀的程序员,十分优秀!

滴滴打车优惠券免费领取
滴滴打车优惠券
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com