Какой часовой пояс использует Hibernate, когда он читает и записывает объект Java Calendar в SQL TIMESTAMP? - PullRequest
18 голосов
/ 07 ноября 2010

Когда Hibernate записывает объект Java Calendar в столбец SQL TIMESTAMP, в какой часовой пояс это делаетсянастроить дату, дату компьютера или ту, которая указана в объекте календаря (или какой-либо другой)?

Когда Hibernate считывает TIMESTAMP в объект календаря, для какого часового поясаэто перевести дату?

Ответы [ 4 ]

16 голосов
/ 07 ноября 2010

Когда Hibernate записывает объект календаря Java в столбец SQL TIMESTAMP, для какого часового пояса он корректирует дату, дату компьютера или дату, указанную в объекте календаря (или какой-либо другой)?

Hiberante 3.x использует следующее в CalendarType (см. HB-1006 ):

public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
    final Calendar cal = (Calendar) value;
    //st.setTimestamp( index,  new Timestamp( cal.getTimeInMillis() ), cal ); //JDK 1.5 only
    st.setTimestamp( index,  new Timestamp( cal.getTime().getTime() ), cal );
}

Таким образом, Hibernate использует PreparedStatement#setTimestamp(int, Timestamp, Calendar) который использует часовой пояс календаря.

Когда Hibernate считывает TIMESTAMP в объект календаря, в какой часовой пояс он переводит дату?

Хорошо,еще раз, давайте посмотрим на класс CalendarType:

public Object get(ResultSet rs, String name) throws HibernateException, SQLException {

    Timestamp ts = rs.getTimestamp(name);
    if (ts!=null) {
        Calendar cal = new GregorianCalendar();
        if ( Environment.jvmHasTimestampBug() ) {
            cal.setTime( new Date( ts.getTime() + ts.getNanos() / 1000000 ) );
        }
        else {
            cal.setTime(ts);
        }
        return cal;
    }
    else {
        return null;
    }

}

Итак, Hibernate создает значение по умолчанию GregorianCalendar, используя текущее время в часовой пояс по умолчанию с языком по умолчанию.


В качестве примечания настоятельно рекомендую прочитать следующий вопрос:

6 голосов
/ 18 января 2013

Я только что потратил 6 часов на аналогичную проблему и подумал, что запишу ее здесь.Hibernate действительно использует часовой пояс JVM, но его можно изменить, расширив CalendarType следующим образом:

public class UTCCalendarType extends CalendarType {

    private static final TimeZone UTC = TimeZone.getTimeZone("UTC");

    /**
     * This is the original code from the class, with two changes. First we pull
     * it out of the result set with an example Calendar. Second, we set the new
     * calendar up in UTC.
     */
    @Override
    public Object get(ResultSet rs, String name) throws SQLException {
        Timestamp ts = rs.getTimestamp(name, new GregorianCalendar(UTC));
        if (ts != null) {
            Calendar cal = new GregorianCalendar(UTC);
            cal.setTime(ts);
            return cal;
        } else {
            return null;
        }
    }

    @Override
    public void set(PreparedStatement st, Object value, int index) throws SQLException {
        final Calendar cal = (Calendar) value;
        cal.setTimeZone(UTC);
        st.setTimestamp(index, new Timestamp(cal.getTime().getTime()), cal);
    }
}

секретный соус здесь:

  rs.getTimestamp(name, new GregorianCalendar(UTC));

Это преобразует часовой пояс из результатаустановить любой часовой пояс, который вы хотите.Поэтому я использовал этот тип для любых календарей UTC и стандартного типа Hibernate для местного времени.Работает гладко, как свисток ...

1 голос
/ 19 апреля 2017

По умолчанию драйвер JDBC определяет, какой часовой пояс использовать.Как правило, часовой пояс JVM используется, если вы не настроите драйвер JDBC на использование собственного часового пояса.

Если вы хотите контролировать, какой часовой пояс используется, вы можете установить часовой пояс на уровне JVM.Если вы хотите, чтобы часовой пояс JVM отличался от часового пояса, используемого базой данных, вам необходимо использовать следующее свойство конфигурации Hibernate 5.2:

<property name="hibernate.jdbc.time_zone" value="US/Eastern"/>

Для получения более подробной информации ознакомьтесь с этой статьей .

0 голосов
/ 08 ноября 2016

Если вы не хотите писать код самостоятельно, вы можете просто использовать библиотеку с открытым исходным кодом DbAssist. После применения этого исправления даты в базе данных будут обрабатываться JDBC, а затем Hibernate как UTC, поэтому вам даже не придется менять свои разрешенные классы.

Например, если вы используете аннотации JPA с Hibernate 4.3.11, добавьте следующую зависимость Maven:

<dependency>
    <groupId>com.montrosesoftware</groupId>
    <artifactId>DbAssist-4.3.11</artifactId>
    <version>1.0-RELEASE</version>
</dependency>

Тогда вы просто применяете исправление:

Для настройки Hibernate + Spring Boot добавьте аннотацию @EnableAutoConfiguration перед классом приложения.

Для файлов HBM необходимо изменить файлы сопоставления сущностей, чтобы сопоставить типы Date с пользовательскими:

<property name="createdAt" type="com.montrosesoftware.dbassist.types.UtcDateType" column="created_at"/>

Если вы хотите узнать больше о том, как применить исправление для различных версий Hibernate (или файлов HBM), обратитесь к github проекта . Вы также можете прочитать больше о проблеме смещения часового пояса в этой статье .

...