Java / Sql-server参数绑定无法按预期进行

时间:2019-06-28 13:01:11

标签: java sql-server jdbc unicode binding

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

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

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

Some facts:

不同编码的µ的字符值是:

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

我们非常感谢您为解决此问题提供的帮助!

1 个答案:

答案 0 :(得分:0)

我现在找到了解决方案。它根本与Sql Server或绑定无关,而是...

默认情况下,Tomcat 7不在UTF-8模式下运行(我当时并不知道)。我们所说的µ来自另一个通过Web服务调用提供此值的应用程序。但是,应用程序默认使用UTF-8。因此,它正在发送UTF-8 µ,但是Web服务并不期望UTF-8,并认为它将是两个字符,并像这样对待它们,用0xC2和0xB5的字符填充内部String变量(这是,对于Sql Server,则为C200B500)。