我有一个像这样的持久化实体的基类:
@EntityListeners(AuditListener.class)
@MappedSuperclass
public abstract class BaseEntity {
@Id
private String id;
private Instant createdAt;
private String createdBy;
private Instant modifiedAt;
private String modifiedBy;
...
在持久化/更新时填充创建/修改字段的侦听器:
public class AuditListener {
@PrePersist
private void onCreate(BaseEntity entity) {
entity.setCreatedAt(Instant.now());
entity.setCreatedBy(getIdUserLogged());
}
@PreUpdate
private void onUpdate(BaseEntity entity) {
entity.setModifiedAt(Instant.now());
entity.setModifiedBy(getIdUserLogged());
}
}
对于通过查询进行的更新,侦听器现在可以工作并且我已经手动设置了值:
@Repository
public interface IngredientRepository extends CrudRepository<Ingredient, String> {
@Modifying
@Query("update Ingredient set active = false, modifiedAt = current_timestamp where id in :removedIds")
int deactivate(@Param("removedIds") Collection<String> toBeRemoved);
}
这在 SpringBoot 2.7.x 上运行良好,但在更新到 SpringBoot 3.0.2 后,应用程序在启动时失败:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ingredientRepository' defined in ...: Could not create query for public abstract int de.digitale_therapiebegleitung.manager_app.services.local.IngredientRepository.deactivate(java.util.Collection,java.lang.String); Reason: Validation failed for query for method public abstract int de.digitale_therapiebegleitung.manager_app.services.local.IngredientRepository.deactivate(java.util.Collection,java.lang.String)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:712)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:692)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:133)
...
Caused by: java.lang.IllegalArgumentException: org.hibernate.query.SemanticException: The assignment expression type [java.sql.Timestamp] did not match the assignment path type [java.time.Instant] for the path [...] [update Ingredient set active = false, modifiedAt = current_timestamp where id in :removedIds]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:175)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:182)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:760)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:662)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:126)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360)
at jdk.proxy2/jdk.proxy2.$Proxy166.createQuery(Unknown Source)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:94)
... 76 common frames omitted
Caused by: org.hibernate.query.SemanticException: The assignment expression type [java.sql.Timestamp] did not match the assignment path type [java.time.Instant] for the path [...] [update Ingredient set active = false, modifiedAt = current_timestamp where id in :removedIds]
at org.hibernate.query.sqm.internal.QuerySqmImpl.verifyUpdateTypesMatch(QuerySqmImpl.java:363)
at org.hibernate.query.sqm.internal.QuerySqmImpl.validateStatement(QuerySqmImpl.java:312)
at org.hibernate.query.sqm.internal.QuerySqmImpl.<init>(QuerySqmImpl.java:212)
at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:744)
... 85 common frames omitted
我找不到 Hibernate 6 中的任何更改来解释更改的内容。 一种解决方案是将
modifiedAt
字段更改为 java.sql.Timestamp ...但不是很好。
https://thorben-janssen.com/migrating-to-hibernate-6/
当 Hibernate 在版本 5 中引入这些类型的专有映射时,它将 Instant 映射到 SqlType.TIMESTAMP 并将 Duration 映射到 Types.BIGINT。 Hibernate 6 改变了这个映射。它现在将 Instant 映射到 SqlType.TIMESTAMP_UTC,将 Duration 映射到 SqlType.INTERVAL_SECOND。
这些新映射似乎比旧映射更适合。因此,他们在 Hibernate 6 中对其进行了更改是件好事。但它仍然破坏了现有应用程序的表映射。如果遇到该问题,可以将配置属性 hibernate.type.preferred_instant_jdbc_type 设置为 TIMESTAMP 并将 hibernate.type.preferred_duration_jdbc_type 设置为 BIGINT。