4

我正在尝试坚持java.time.LocalDateTime使用 Hibernate 和 JPA。我使用了 Jadira 框架(“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)的形式存储/检索到我的 MySQL 数据库中。DATETIME

唯一的问题是数据库中的值与 Java 中字段的正确时间值相差 +2 小时。我在 CEST (UTC+2) 所以我明白这是时区的一些问题。我调试了代码,PersistentLocalDateTime这就是我发现的。

  1. PersistentLocalDateTime正在使用org.jadira.usertype.dateandtime.threeten.columnmapper.AbstractTimestampThreeTenColumnMapper
  2. AbstractTimestampThreeTenColumnMapper字段ZoneOffset databaseZone默认设置为ZoneOffset.of("Z")(UTC)。
  3. 因为它认为我的数据库在 UTC 时区(并且应用程序在 UTC+2),所以它在转换到数据库期间增加了两个小时(并在从数据库转换期间从我的时间中减去了两个小时)。所以在应用程序中我看到了正确的日期和时间,但在数据库中我没有。

我发现 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。为什么它会返回nulljava.time.ZoneOffset因为来自和的时区 IDjava.util.TimeZone不匹配。据我所知,匹配的唯一可能值是Z. 任何其他值都会导致异常。

有什么方法可以正确设置吗?还是 Jadira 框架中的错误?

4

1 回答 1

1

它看起来像一个严重的错误。问题是 jadira.usertype.databaseZone 参数被解析为 ZoneOffset 而不是 ZoneId。这样,resolveCalendar 方法比较了 2 种不同类型的 Zone 和 Offset。有趣的是,参数名为 databaseZone 但它不包含区域。它只包含偏移量。

https://github.com/JadiraOrg/jadira/issues/42

https://github.com/JadiraOrg/jadira/issues/43

于 2015-08-31T15:36:13.950 回答