Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Когда Hibernate записывает объект Java Calendar в столбец 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, используя текущее время в часовом поясе по умолчанию с локалью по умолчанию.


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

Ответ 2

Я только что провел 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 для локального времени. Работы скользят как свисток...

Ответ 3

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

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

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

Подробнее см. в этой статье.

Ответ 4

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

Например, если вы используете 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 Настройка загрузки добавьте аннотацию @EnableAutoConfiguration до класса приложения.

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

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

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