如何使用java.time.LocalDateTime设置jadira PersistentLocalDateTime?

时间:2015-08-05 08:10:33

标签: java hibernate jpa java-8 jsr

我正在尝试使用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&#34 )。我创建了package-info.java文件并在那里创建了@TypeDefs({@TypeDef(defaultForType = java.time.LocalDateTime.class, typeClass = org.jadira.usertype.dateandtime.threeten.PersistentLocalDateTime.class)})。我测试了解决方案,java.time.LocalDateTime字段在DATETIME列(几乎)中正确存储/检索到我的MySQL数据库。

唯一的问题是数据库中的值与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),所以它在转换到数据库期间增加了两个小时(并且从数据库转换过程中减去了两个小时)。所以在应用程序中我看到了正确的日期和时间,但在数据库中我没有。
  4. 我发现可以向@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.ZoneOffsetjava.util.TimeZone的时区ID不匹配。据我所知,匹配的唯一可能值是Z。任何其他值都会导致异常。

    有没有办法正确设置?或者它是Jadira框架中的错误?

1 个答案:

答案 0 :(得分:1)

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

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

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