我试图使用Hibernate和JPA保留java.time.LocalDateTime
。我使用了Jadira Framework(“org.jadira.usertype:usertype.core:3.2.0.GA”和“org.jadira.usertype:usertype.extended:3.2.0.GA”)。我创建了package-info.java
文件,并在那里创建了@TypeDefs({@TypeDef(defaultForType = java.time.LocalDateTime.class, typeClass = org.jadira.usertype.dateandtime.threeten.PersistentLocalDateTime.class)})
。我测试了解决方案,并将java.time.LocalDateTime
字段正确地存储/检索到DATETIME
列中的mysqlt数据库中(几乎为)。
唯一的问题是,数据库中的值是Java中字段中正确时间值的+2小时。我处于CEST(UTC + 2),所以我知道这是时区问题。我调试了PersistentLocalDateTime
的代码,这就是我发现的内容。
PersistentLocalDateTime
正在使用org.jadira.usertype.dateandtime.threeten.columnmapper.AbstractTimestampThreeTenColumnMapper
AbstractTimestampThreeTenColumnMapper
默认将ZoneOffset databaseZone
字段设置为ZoneOffset.of("Z")
(UTC)。 我发现a可以向
@TypeDef
添加参数,因此我将其指定如下:@TypeDef(defaultForType = LocalDateTime.class, typeClass = PersistentLocalDateTime.class,
parameters = {
@Parameter(name = "databaseZone", value = "+02:00")
}),
但我有一个例外:
java.lang.IllegalStateException: Could not map Zone +02:00 to Calendar
at org.jadira.usertype.dateandtime.threeten.columnmapper.AbstractTimestampThreeTenColumnMapper.getHibernateType(AbstractTimestampThreeTenColumnMapper.java:59)
我调试了一点。
AbstractTimestampThreeTenColumnMapper
有两种方法:public final DstSafeTimestampType getHibernateType() {
if (databaseZone == null) {
return DstSafeTimestampType.INSTANCE;
}
Calendar cal = resolveCalendar(databaseZone);
if (cal == null) {
throw new IllegalStateException("Could not map Zone " + databaseZone + " to Calendar");
}
return new DstSafeTimestampType(cal);
}
private Calendar resolveCalendar(ZoneOffset databaseZone) {
String id = databaseZone.getId();
if (Arrays.binarySearch(TimeZone.getAvailableIDs(), id) != -1) {
return Calendar.getInstance(TimeZone.getTimeZone(id));
} else {
return null;
}
}
getHibernateType
方法引发异常,因为resolveCalendar
方法返回null
。为什么返回null
?因为java.time.ZoneOffset
和java.util.TimeZone
中的时区ID不匹配。据我所知,唯一可能匹配的值是Z
。任何其他值都会导致异常。有什么办法可以正确设置此设置吗?还是Jadira框架中的错误?
最佳答案
它看起来像一个严重的错误。问题在于jadira.usertype.databaseZone参数被解析为ZoneOffset而不是ZoneId。这样,resolveCalendar方法会比较两种不同的类型Zone和Offset。有趣的是,参数名为databaseZone,但其中不包含区域。它仅包含偏移量。
https://github.com/JadiraOrg/jadira/issues/42
https://github.com/JadiraOrg/jadira/issues/43