MariaDB编写的Statement不会为where子句转换字符集

时间:2014-10-15 11:00:28

标签: java jdbc mariadb

我在这里遇到一个问题,看起来像MariaDB中的一个错误,但在将它发布到MariaDB错误数据库之前我想在这里发布,也许我做错了。

使用以下代码可以轻松复制问题:

public static void main(String[] args) throws ReplicationException, SQLException {
  byte[] cb3 = {-61, -92, 98, -29, -125, -70, -61, -87}; //equals to "äb?é", with “?” being a japanese character
  String corrupt = new String(cb3, Charsets.UTF_8);
  MariaDB db = new MariaDB();
  Connection conn = db.getConnection();

  //byte[] latinBytes =  corrupt.getBytes(Charset.forName("ISO-8859-1")); //workaround
  //corrupt = new String(latinBytes, Charset.forName("ISO-8859-1")); //workaround

  PreparedStatement sqlInsert = conn.prepareStatement("insert into prep values (?)");
  sqlInsert.setString(1, corrupt);
  sqlInsert.execute();
  conn.commit();
  System.out.println("insert ok");

  PreparedStatement sqlSelect = conn.prepareStatement("select * from prep where text=? ");
  sqlSelect.setString(1, corrupt);
  sqlSelect.execute();
}

在我的MariaDB(有字符集latin1!)上,有一个表格准备:“create table prep(text varchar(10));” 当我运行此代码时,插入工作完美:日语字符转换为“?”,如预期的那样。 但是,sqlSelect根本不起作用,并产生令人担心的错误消息“非法混合排序(latin1_general_cs,IMPLICIT)和(utf8_general_ci,COERCIBLE)操作'='”。

如果我将sql更改为“select * from prep where text =?collat​​e latin1_general_cs”,我收到错误消息“COLLATION'latin1_general_cs'对CHARACTER SET'utf8'无效”。因此我得出结论,我的绑定变量“corrupt”没有转换为where子句的latin1。但是,我期望这种转​​换,因为它适用于插入。

有一种可行的解决方法:如果激活两行“// workaround”,则在将数据库提供给数据库之前,将在java中转换该字符串。但是,我觉得这不应该是必要的。

在oracle数据库上运行相同的代码不会产生错误。有人可以在mysql数据库上运行吗?

那么,这看起来像是一个错误,或者我错过了什么。

其他信息:
MariaDB版本10.0.14,适用于java的MariaDB客户端库:1.1.7
jdbc连接字符串如下所示:

"jdbc:mariadb://localhost:3306/myDb?rewriteBatchedStatements=true&useServerPrepStmts=false"  

要启动数据库,我使用默认的“my-large.ini” 我使用以下代码创建了数据库:

create database myDb
DEFAULT CHARACTER SET latin1 
COLLATE latin1_general_cs;

更新:我向mariaDB团队提交了一份错误报告: https://mariadb.atlassian.net/browse/CONJ-117

1 个答案:

答案 0 :(得分:1)

在使用MariaDB和MySQL进行测试代码试验后,我可以确认它们的行为似乎有所不同。但是,我不一定称它为MariaDB中的“bug”。

它似乎与数据库服务器本身的响应不同。我尝试使用MariaDB Java Client 1.7和MySQL Connector / J 5.1.27将更改应用于MariaDB 10.0.13服务器,并且它们都给出了相同的结果:MariaDB能够自动翻译来自的第一个,第二个和第四个字符UTF-8到Latin1,但它在第三个(日语)字符U + 30FA(UTF-8中的0xE3 0x83 0xBA)上被阻塞,因为没有Latin1等价物。

这是有道理的。在某些情况下,MySQL可能很方便(并且静默地)将所有不可翻译的字符映射到'?',但这可能并不总是可取的。您设计的解决方法是告诉Java明确强制非Latin1字符'?',然后将 传递给MariaDB。你觉得它没有必要,但我不确定我同意。

因此,它是否是MariaDB中的“bug”实际上取决于MariaDB是否正在运行“as designed”。换句话说,仅仅因为MariaDB的行为与MySQL不同,并不一定会成为MariaDB中的错误。例如,在MariaDB 5.5.31中,他们改变了CAST()的行为来解决二进制字符串文字的解释问题,结果是

  

这引入了与以前版本的MariaDB以及所有MySQL版本

的不兼容性

也就是说,您可以随时将您的问题报告为MariaDB错误并查看它们的响应方式。