spring-data-jpa 不适用于 java 8 LocalTime
spring-data-jpa not working with java 8 LocalTime
Spring 数据存储库(版本 1.8)的查询派生机制无法与 Java 8 LocalTime 一起正常工作。有人可以告诉我我做错了吗还是错误?
我将开始时间存储在10:00上午
LocalTime startingTime = LocalTime.of(10,0);
myEntity.setHorai(startingTime);
myEntityRepository.save(myEntity);
然后我询问所有开始时间大于 08:00 am:
的实体
LocalTime zeroEight = LocalTime.of(8, 0);
List<MyEntity> ents = myEntityRepository.findByStartingTimeAfter(zeroEight);
我可以看到 Hibernate(我使用的是 Hibernate 4.3 版。7.Final)执行此操作:
Hibernate: select <all fields> from MyEntity m_ where m_.startingTime>?
TRACE 2015-03-27 12:08:51,283 o.h.type.descriptor.sql.BasicBinder: binding parameter [1] as [VARBINARY] - [08:00]
所以列表应该包含 1 个元素,但它有 0 个元素。
如果不是 findByStartingTimeAfter
我使用 findByStartingTimeBefore
它 returns 1 个元素,但我不确定这是不是因为我误解了前后的工作方式。我试过 findByStartingTimeGreaterThan
但同样失败了。
也许查询派生机制不适用于 Java 8 LocalTime?
可能是 Hibernate 的问题,即没有正确比较 VARBINARY 数据(我可以看到 LocalTime 存储为 BLOB,但它作为 LocalTime 正确存储和检索)?
我正在使用 postgres 9.2,但我认为问题不在 postgres 上。
答案在问题中。 Hibernate 还不支持 java.time 类(它将在 5.0 版中提供)。因此它将 LocalTime 视为 Serializable 实例,并将序列化的 LocalTime 实例作为字节数组简单地存储在 varbinary 列中。因此,>
运算符对此类列没有多大意义,也不会按时间顺序比较 LocalTime 值。
您可以定义自己的自定义 Hibernate 类型,或使用 jadira(为您定义此自定义类型),以将 LocalTime 值存储在适当的列类型中。
如果没有进一步的映射信息,Hibernate 会将 JDK 8 个日期视为 BLOB,因此不能再对这些字段应用任何比较操作。
一个解决方案是使用 Jadira User Types library 自定义这些类型映射到数据库的方式。
如果您只处理非时区类型(例如 LocalDate
、LocalDateTime
),最简单的方法是使用 Spring 数据附带的 JPA 2.1 转换器JPA 1.8。只需确保 Jsr310JpaConverters
是持久性 classes 的列表(通过扫描相应的包或在您的 persistence.xml
中手动列出 class)和这些 JDK 8 个特定的 date/time 类型被透明地映射到 Date
,这样任何持久性提供者都可以立即持久化它们。在 blog post announcing new features in the Spring Data Fowler release train.
中找到更多相关信息
Spring 数据存储库(版本 1.8)的查询派生机制无法与 Java 8 LocalTime 一起正常工作。有人可以告诉我我做错了吗还是错误?
我将开始时间存储在10:00上午
LocalTime startingTime = LocalTime.of(10,0);
myEntity.setHorai(startingTime);
myEntityRepository.save(myEntity);
然后我询问所有开始时间大于 08:00 am:
的实体LocalTime zeroEight = LocalTime.of(8, 0);
List<MyEntity> ents = myEntityRepository.findByStartingTimeAfter(zeroEight);
我可以看到 Hibernate(我使用的是 Hibernate 4.3 版。7.Final)执行此操作:
Hibernate: select <all fields> from MyEntity m_ where m_.startingTime>?
TRACE 2015-03-27 12:08:51,283 o.h.type.descriptor.sql.BasicBinder: binding parameter [1] as [VARBINARY] - [08:00]
所以列表应该包含 1 个元素,但它有 0 个元素。
如果不是 findByStartingTimeAfter
我使用 findByStartingTimeBefore
它 returns 1 个元素,但我不确定这是不是因为我误解了前后的工作方式。我试过 findByStartingTimeGreaterThan
但同样失败了。
也许查询派生机制不适用于 Java 8 LocalTime?
可能是 Hibernate 的问题,即没有正确比较 VARBINARY 数据(我可以看到 LocalTime 存储为 BLOB,但它作为 LocalTime 正确存储和检索)?
我正在使用 postgres 9.2,但我认为问题不在 postgres 上。
答案在问题中。 Hibernate 还不支持 java.time 类(它将在 5.0 版中提供)。因此它将 LocalTime 视为 Serializable 实例,并将序列化的 LocalTime 实例作为字节数组简单地存储在 varbinary 列中。因此,>
运算符对此类列没有多大意义,也不会按时间顺序比较 LocalTime 值。
您可以定义自己的自定义 Hibernate 类型,或使用 jadira(为您定义此自定义类型),以将 LocalTime 值存储在适当的列类型中。
如果没有进一步的映射信息,Hibernate 会将 JDK 8 个日期视为 BLOB,因此不能再对这些字段应用任何比较操作。
一个解决方案是使用 Jadira User Types library 自定义这些类型映射到数据库的方式。
如果您只处理非时区类型(例如 LocalDate
、LocalDateTime
),最简单的方法是使用 Spring 数据附带的 JPA 2.1 转换器JPA 1.8。只需确保 Jsr310JpaConverters
是持久性 classes 的列表(通过扫描相应的包或在您的 persistence.xml
中手动列出 class)和这些 JDK 8 个特定的 date/time 类型被透明地映射到 Date
,这样任何持久性提供者都可以立即持久化它们。在 blog post announcing new features in the Spring Data Fowler release train.