当Hibernate 将<{3}}对象写入SQL Calendar
列时,它会调整日期,计算机的日期或在日历对象(或其他一些)中指定的?
当Hibernate 将TIMESTAMP
读入日历对象时,它会将日期转换为哪个时区?
答案 0 :(得分:15)
当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
。
作为旁注,我强烈建议您阅读以下问题:
答案 1 :(得分:6)
我只花了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类型一起使用。像哨子一样光滑......
答案 2 :(得分:1)
默认情况下,由JDBC Driver决定使用哪个时区。通常,除非您将JDBC驱动程序配置为使用自定义时区,否则将使用JVM时区。
如果要控制使用的时区,可以在JVM级别设置时区。如果您希望JVM时区与数据库使用的时区不同,则需要使用以下Hibernate 5.2配置属性:
<property name="hibernate.jdbc.time_zone" value="US/Eastern"/>
有关详细信息,请查看this article。
答案 3 :(得分:0)
如果您不想自己编写代码,可以使用开源库DbAssist
。应用此修复程序后,数据库中的日期将由JDBC处理,然后Hibernate将作为UTC处理,因此您甚至不必更改权限类。
例如,如果您在Hibernate 4.3.11中使用JPA Annotations,请添加以下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文件)应用修复程序的更多信息,请参阅the project's github。您还可以在此article中详细了解时区转换问题。