Привязка параметров Java / Sql-сервера не работает должным образом - PullRequest
0 голосов
/ 28 июня 2019

Мы замечаем странное поведение в нашем приложении относительно параметров связывания.Мы используем Java с JDBC для подключения к базе данных Sql Server.В ячейке таблицы у нас есть значение «µ», и мы сравниваем его с параметром связывания, который также имеет значение «µ».

Теперь в SQL-выражении типа "... где значение! =?" , где 'значение' - это значение 'µ' в базе данных и?переменная связывания, которая также установлена ​​в «µ», мы замечаем, что получаем запись, хотя мы ожидаем, что «µ» будет равняться «µ».

Метод, который мы используем для заполнения параметра связыванияis 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. Jdbc-библиотека - sqljdbc 4.2

Любая помощь для решения этой проблемы очень ценится!

1 Ответ

0 голосов
/ 02 июля 2019

Я сейчас нашел решение.Это никак не связано с Sql Server или связыванием, но вместо этого ...

Tomcat 7 по умолчанию не работает в режиме UTF-8 (я не знал об этом).Μ, о котором мы говорим, происходит из другого приложения, которое предоставляет это значение через вызовы веб-службы.Однако это приложение использует UTF-8 по умолчанию.Итак, он отправлял UTF-8 µ, но веб-сервис не ожидал UTF-8 и думал, что это будет два символа, и обрабатывал их следующим образом, заполняя внутреннюю переменную String символом для 0xC2 и 0xB5 (что, для сервера Sql, C200B500).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...