我试图使用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)。
  • 因为考虑到我的数据库位于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。为什么返回null?因为java.time.ZoneOffsetjava.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

    07-24 19:00