Столбцы Date в SQL-Server (MSSQL-JDBC 3.0), запущенные под Java 1.7.0, получены в течение 2 дней в прошлом
У меня странные эффекты при извлечении столбцов типа DATE из SQLServer2008 с помощью Microsoft JDBC-Driver версии 3.0 при работе под официальным Oracle JDK 1.7.0. ОС хоста - Windows Server 2003.
Все столбцы Date извлекаются как два дня в прошлом относительно значения, фактически сохраненного в столбце.
Я подготовил минимальный пример кода, чтобы проверить это (таблица тестов и данные):
CREATE TABLE Java7DateTest (
dateColumn DATE
);
INSERT INTO Java7DateTest VALUES('2011-10-10');
код:
public class Java7SQLDateTest {
public static void main(final String[] argv) {
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection connection = DriverManager.getConnection(
"jdbc:sqlserver://192.168.0.1:1433;databaseName=dbNameHere",
"user", "password");
PreparedStatement statement = connection.prepareStatement("SELECT * FROM Java7DateTest");
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
final java.sql.Date date = resultSet.getDate("dateColumn");
final String str = resultSet.getString("dateColumn");
System.out.println(date + " (raw: " + str + ")");
}
resultSet.close();
statement.close();
connection.close();
} catch (final Throwable t) {
throw new RuntimeException(t.getMessage(), t);
}
}
}
Запуск этого кода на вышеприведенных конфигурациях печатает: "2011-10-08 (raw: 2011-10-08)".
В JRE 1.6.0_27 он печатает: "2011-10-10 (raw: 2011-10-10)"
Я не мог найти ничего похожего на мою проблему с Google, поэтому я предполагаю, что ее либо что-то глупое я забыл, либо никто еще не использует Java7.
Может ли кто-нибудь подтвердить эту проблему? Каковы мои альтернативы, если я все еще хочу использовать Java7?
Изменить: Проблема возникает даже при работе с -Xint, поэтому ее не вызывают ошибки Hotspot.
Edit2: старые драйверы (Microsoft 1.28) работают правильно с JDK1.7.0 (мы использовали этот драйвер, возможно, два года назад, я думаю).
jTDS также отлично работает с примером. Я рассматриваю возможность перехода на jTDS, но я неохотно это делаю, потому что не имею ни малейшего представления о влиянии на нашу продуктивную среду. В идеале это должно сработать, но это то, что я верил, когда я переключил свой блок разработчиков на Java7.
В рабочей среде есть одна довольно жирная база данных, которая слишком велика для создания копии для тестирования (или, скорее, у нашего сервера осталось так мало диска). Поэтому настройка тестовой среды для этого приложения не является чрезмерной, поэтому для этого мне нужно будет сшить сжатую базу данных.
Edit3: jTDS имеет свой собственный набор уловов. Я нашел поведенческую разницу, которая ломает одно из наших приложений. ResultSet.getObject() возвращает разные типы объектов для столбцов SmallInt в зависимости от драйвера (Short vs Integer). Кроме того, jTDS не реализует интерфейс подключения JDBC4, Connect.isValid() не поддерживается.
Edit4: на прошлой неделе я заметил, что MSSQL-JDBC 3.0 отказывается подключиться к любой базе данных после обновления до JDK1.6.0_29. jTDS это тогда... вчера мы переключили продуктивный сервер (я фиксировал места буксировки, где приложение полагалось на особенности драйвера), и до сих пор у нас не было проблем.
Ответы
Ответ 1
У меня нет ответа для вас. Но я воссоздал вашу ситуацию, как вы описали. То же самое с драйверами jdbc v3.101 и v3.202 и v4.ctp3 при запуске под jdk1.7. Однако драйвер v2 из MS дает ожидаемый ответ как в jdk1.6, так и в jdk1.7. Если вам требуется быстрое исправление и вы можете перейти на старый драйвер jdbc, это может сработать для вас.
Другие мысли о том, как драйвер MS jdbc обрабатывает даты и преобразование объектов Date между SQL Server и jvm. Поскольку память даты не имеет часового пояса, интерпретация объекта Date с помощью драйвера основана на часовом поясе по умолчанию для машины, на которой запущен драйвер jdbc. Например, если вы храните smalldate от "2011-10-11 12:00" и извлекаете его с машины с часовым поясом по умолчанию, установленным на GMT-7, тогда итоговое время UTC объекта Date будет "2011-10 -11 19:00 '. Возможно, что в jdk1.7 есть некоторые изменения, которые влияют на этот процесс преобразования в драйвере, что приводит к дикому смещению. Вы можете экспериментировать с методом ResultSet.getDate(столбец, календарь), чтобы узнать, получает ли календарь с определенным часовым поясом нужный результат или помогает понять, почему вы видите странное смещение при преобразовании.
Ответ 2
Благодарим вас за отзыв. Драйвер Microsoft JDBC для SQL Server еще не поддерживает JRE 1.7.
Мы знаем о проблеме getDate между нашим драйвером JDBC и JRE 1.7, и мы изучаем публикацию исправления, позволяющего клиентам продвигаться вперед с непроизводственным тестированием нашего драйвера с помощью JRE 1.7.
Мы опубликуем ссылку на исправление в нашем блоге после ее появления.
http://blogs.msdn.com/b/jdbcteam/
Исправление доступно. http://blogs.msdn.com/b/jdbcteam/archive/2012/01/20/hotfix-available-for-date-issue-when-using-jre-1-7.aspx
Наш блог также содержит информацию об известных проблемах с JRE 1.6u29 и 1.6u30.
Шамита Редди
Менеджер программ - Драйвер Microsoft JDBC для SQL Server
Ответ 3
У меня нет настройки SQL Server, но я не могу воспроизвести вашу проблему с PostgreSQL 9.0 и MySQL 5.1 в Windows 7 x64 с JDK 1.7.0. Таким образом, JDK 1.7.0 можно исключить из подозреваемого. У меня сложилось впечатление, что драйвер JDBC SQL Server виноват здесь. Я бы предложил вместо этого использовать jTDS JDBC-драйвер. Его всегда хвалят за его лучшую производительность и стабильность, в отличие от MS-предоставленного драйвера SQL Server JDBC.
Ответ 4
Информацию и ссылку для загрузки для hotpatch из Microsoft Support можно найти здесь:
http://support.microsoft.com/kb/2652061
У меня возникла одна и та же проблема, когда дата была отключена на два дня, и этот hotpatch исправил ее.
Ответ 5
Это также проблема в OpenJDK 1.6.0_20. Однако драйвер mssql отлично работает с Sun JRE 1.6.0_16.