Java/Sql-server 参数绑定没有按预期工作

我们注意到我们的应用程序中有一个关于绑定参数的奇怪行为。我们使用带有 JDBC 的 Java 连接到 Sql Server 数据库。在表格单元格中,我们有值“µ”,我们将其与绑定参数进行比较,绑定参数也设置为值“µ”。


现在,在像“... where value !=?”这样的 sql 语句中 , 其中 'value' 是数据库中 'µ' 的值, ? 绑定变量也设置为“µ”,我们注意到我们得到了一条记录,尽管我们希望“µ”等于“µ”。


我们用来填充绑定参数的方法是java.sql.PreparedStatement.setString(int, String)。


一些事实:


μ在不同编码下的字符值为:


ASCII (ISO-8859-1) : 0xB5


UTF-8 : 0xC2B5


UTF-16 (= Java) : 0x00B5

现在我做了一些调查,看看数据库实际看到了哪些字节。因此,我尝试了这样的 sql 语句:


select convert(VARBINARY(MAX), value), --  selects µ from database table

       convert(VARBINARY(MAX), N'µ'),  --  selects µ from literal

       convert(VARBINARY(MAX), ?)      --  selects µ from bind parameter

from ...

三个值的结果是:


B500

B500

C200B500     <-- Here is the problem!

因此,数据库中 µ 的内部表示和 NVARCHAR 文字是 B500。


现在我们无法理解这里发生了什么。我们在 Java 变量中有“µ”的值(内部应该是 0x00B5)。当它作为绑定变量传递时,似乎被转换为 UTF-8(这使得字节序列为 0xC2B5),然后数据库将其视为两个字符,从而使字符序列 C200B500。


让事情变得更加混乱:


(1) 在具有不同数据库的另一台机器上,相同的代码按预期工作。三行的结果是 B500/B500/B500,因此绑定变量被转换为正确的 B500。


(2) 在同一台机器上,相同的数据库但不同的程序(但使用相同的 jdbc 驱动库和相同的连接参数)这也按预期工作,给出 B500/B500/B500 的结果。


一些额外的事实,也许它们很重要: 数据库是 Sql Server 2014 Java 是 Java 7 有问题的应用程序是在 Tomcat 7 中运行的 webapp。Jdbc 库是 sqljdbc 4.2


非常感谢任何解决此问题的帮助!


慕仙森
浏览 67回答 1
1回答

杨魅力

我现在找到了解决方案。它与 Sql Server 或绑定完全没有关系,而是......默认情况下,Tomcat 7 不以 UTF-8 模式运行(我不知道这一点)。我们谈论的 µ 来自另一个通过网络服务调用提供此值的应用程序。但是,此应用程序默认使用 UTF-8。因此,它发送了一个 UTF-8 µ,但 Web 服务并不期望 UTF-8 并认为它是两个字符,并像这样处理它们,用 0xC2 和 0xB5 的字符填充内部 String 变量(这是,对于 SQL Server,C200B500)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java