java - Java / Sql-server 参数绑定没有按预期工作
问题描述
我们注意到我们的应用程序中有一个关于绑定参数的奇怪行为。我们使用 Java 和 JDBC 连接到 Sql Server 数据库。在表格单元格中,我们有值“μ”,我们将它与绑定参数进行比较,该参数也设置为值“μ”。
现在,在一个 sql 语句中,如“... where value != ?” , 其中 '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
非常感谢任何帮助解决这个问题!
解决方案
我现在找到了解决方案。它根本与 Sql Server 或绑定无关,而是...
默认情况下,Tomcat 7 不以 UTF-8 模式运行(我不知道这一点)。我们正在谈论的 µ 来自另一个通过 web 服务调用提供此值的应用程序。但是,此应用程序默认使用 UTF-8。所以,它正在发送一个 UTF-8 µ,但 web 服务没想到 UTF-8 并认为它会是两个字符,并像这样对待它们,用 0xC2 和 0xB5 的字符填充内部 String 变量(即, 对于 Sql Server, C200B500)。
推荐阅读
- jenkins - Jenkins - 安装插件失败,“无法找到请求目标的有效认证路径”
- powerbi - Powerbi 中的组内累积和图
- python - 在 Python 3 中将 XLS 文件转换为 XLSX?
- r - 使用 ggplot2 中的脚本 l (\ell) 保存 pdf/eps 图
- javascript - 打开带有附件的电子邮件客户端后调用 JavaScript 函数不起作用
- c# - 根据传入参数更新传出参数
- python - Python中的并行嵌套for循环
- python - 如何在 Python 中构建对话分析仪表板?
- multithreading - 多线程、跟踪垃圾收集器和原生 C API
- jquery - Octobercms 使用 Ajax 填充表单域