Как должна работать временная метка SQL Server2 в JDBC?

У меня возникли проблемы с использованием timestamp2 вместо Timestamp в SQL Server 2008. По-видимому, rs.getTimestamp имеет очень разное поведение между timestamp и timestamp2. Однако я не могу найти никакой документации, в которой говорилось бы, что должна быть разница или что я должен использовать что-то другое. Интересно, я просто делаю что-то не так?

Окружающая среда:

  • Пробовал как на SQL Express 2008 (10.0), так и на SQL Server 2008 R2 (10.5).
  • sqljdbc4.jar версии 3.0, размер 537 303 байт, CRC-32=a0aa1e25, MD5=402130141d5f2cee727f4371e2e8fd8a.
  • Ява 1.6

Вот модульный тест, демонстрирующий проблему. Единственная «магия» — это «Db.getConnection()», которую вы можете заменить соответствующим кодом. Тест одинаков как для datetime, так и для datetime2, но тест datetime2 терпит неудачу с датой, которая предшествует 2 дням. Я рассматриваю все времена в БД как GMT/UTC, и я не пытался добавить информацию о часовом поясе в данные базы данных для данных datetime2.

    private void testTimestamp(TimeZone gmtTz, Connection conn, String query,
                    Calendar expectedCal) throws SQLException
    {
            PreparedStatement stmt = conn.prepareStatement(query);
            ResultSet rs = stmt.executeQuery();
            while (rs.next())
            {
                    // Note the expectedCal has a GMT timezone.
                    Date actualTs = rs.getTimestamp("dt", expectedCal);

                    // Just print out the time difference
                    long diff = actualTs.getTime() - expectedCal.getTimeInMillis();
                    System.out.println("Diff=" + diff);

                    // Do the test to make sure they are the same
                    // In practice, this succeeds for datetime and fails for datetime2
                    Assert.assertEquals(expectedCal.getTimeInMillis(), actualTs.getTime());
            }
    }

    @Test
    public void testDateTime() throws SQLException
    {
            Connection conn = Db.getConnection();
            TimeZone gmtTz = TimeZone.getTimeZone("GMT");
            String query;

            Calendar expectedCal = Calendar.getInstance(gmtTz);
            expectedCal.clear();
            expectedCal.set(2011, 10, 02, 11, 17);

            query = "select CAST('2011-11-02 11:17:00' as datetime) as dt";
            testTimestamp(gmtTz, conn, query, expectedCal);

            query = "select CAST('2011-11-02 11:17:00.0000000' as datetime2) as dt";
            testTimestamp(gmtTz, conn, query, expectedCal); // results in an error
    }

Является ли мой единственный вариант вернуться к отметке времени?

РЕДАКТИРОВАТЬ: Для будущих сотрудников Google, использующих sqljdbc4.jar версии 3.0, тест не проходит в Linux, но проходит в Windows. Я еще не пробовал sqljdbc4.jar версии 4.0, которая поставляется с SQL Server 2012.


person Pixel    schedule 02.11.2011    source источник
comment
Насколько различаются два значения в случае сбоя? Всегда ли эта разница остается постоянной? Кроме того, вы можете сбросить expectedCal после каждого теста? Кроме того, работает ли это, если вы передаете не календарь GMT, а экземпляр по умолчанию Calendar?   -  person Sanjay T. Sharma    schedule 02.11.2011
comment
Спасибо за ваши идеи. Datetime2 всегда на 2 дня (48 часов) раньше ожидаемого времени. Создание нового календаря с теми же значениями имеет точно такую ​​же разницу. Использование календаря по умолчанию имеет точно такое же отличие. Пока проблема, как бы я ее ни нарезал.   -  person Pixel    schedule 02.11.2011
comment
Хорошо, это сужает проблему. Еще две вещи, если вы можете: 1) Он по-прежнему дает неправильное значение, если вы удаляете дополнительную точность, то есть часть .000000 2) Возможно ли для вас попробовать его с помощью другого драйвера JTDS?   -  person Sanjay T. Sharma    schedule 03.11.2011
comment
Удаление точности не имело значения. JTDS (о котором раньше не слышал, спасибо за ссылку) проходит. sqljdbc4.jar (версия 2.0) работает. Но sqljdbc4.jar (версия 3.0) не работает. Варианты сейчас, наверное, есть. использовать jtds; б. используйте sqljdbc4.jar версии 2.0; в. конвертировать поля БД из datetime2 в datetime. Или д. сообщите об ошибке в Microsoft и подождите, пока они исправят свою проблему.   -  person Pixel    schedule 03.11.2011
comment
Обсуждение комментариев становится слишком длинным, поэтому я перенес свой ответ в новый пост.   -  person Sanjay T. Sharma    schedule 03.11.2011


Ответы (2)


Я помню, что не слышал хороших отзывов о том, что официальный драйвер SQL Server и JTDS предпочтительнее (хотя я не могу найти эту ссылку). Лично я бы выбрал JTDS (конечно, с тщательным тестированием) или вернулся к версии, которая не вызывает проблем. Я не работал с SQL Server, но, судя по всему, datetime2 является предпочтительным типом данных, поэтому я бы не хотел возвращаться назад. Вариант (d) не очень хороший вариант ИМО. :)

person Sanjay T. Sharma    schedule 03.11.2011
comment
Спасибо за ваш вклад, Санджай. Вы действительно помогли мне понять, какие есть варианты, и это здорово. Я не уверен на 100%, какой вариант я выберу. Как вы сказали, JTDS потребует тщательного тестирования. Я, вероятно, вернусь к sqljdbc4.jar версии 2 или преобразую поля обратно в дату и время в ближайшем будущем и внимательно рассмотрю JTDS для долгосрочного решения. - person Pixel; 03.11.2011
comment
Становится интереснее. При использовании sqljdbc4.jar версии 3.0 тест не проходит в Linux (моя производственная среда), но проходит в Windows. Я не думаю, что это меняет мои варианты, но эта информация может быть полезна для тех, кто найдет это в будущем. Так что Microsoft не совсем сошла с ума. - person Pixel; 03.11.2011

Если вы используете Sun JRE 1.7 с драйвером Microsoft JDBC 3.0, см. эту запись в блоге http://blogs.msdn.com/b/jdbcteam/archive/2012/01/20/hotfix-available-for-Дата-выпуск-при-использовании-jre-1-7.aspx.

Если вы считаете, что обнаружили ошибку в нашем драйвере, вы можете сообщить об этом через Microsoft Connect. https://connect.microsoft.com/SQLServer

person Microsoft JDBC Driver    schedule 19.04.2012