【发布时间】:2019-04-23 15:13:11
【问题描述】:
每当我使用 JPA 插入或更新实体时,我想在数据库 systimestamp 值上设置更新日期列。注意我要使用数据库节点的时间,而不是应用服务器的时间。 JPA 或 EclipseLink 注释可以做到这一点吗?
【问题讨论】:
标签: java database jpa orm eclipselink
每当我使用 JPA 插入或更新实体时,我想在数据库 systimestamp 值上设置更新日期列。注意我要使用数据库节点的时间,而不是应用服务器的时间。 JPA 或 EclipseLink 注释可以做到这一点吗?
【问题讨论】:
标签: java database jpa orm eclipselink
some JPA providers 支持这样的功能,遗憾的是 Eclipselink 不是其中之一。
幸运的是,自定义的 EclipseLink 属性转换器机制允许您在转换期间访问Session,因此以下解决方法有效:
@Converter(name = "database-timestamp", converterClass = DatabaseTimestampFieldConverter.class)
@Entity
public class AuditedEntity {
@Id
@GeneratedValue
private Long id;
private String name;
...
@Convert("database-timestamp")
private Timestamp updatedDate;
@PreUpdate
protected void preUpdate() {
updatedDate = null; // needed to trigger the conversion; if you don't want the extra method here, use @EntityListeners instead
}
}
其中DatabaseTimestampFieldConverter定义为:
public class DatabaseTimestampFieldConverter implements Converter {
@Override
public Object convertObjectValueToDataValue(Object objectValue, Session session) {
return session.executeQuery(new ValueReadQuery("SELECT CURRENT_TIMESTAMP"));
}
@Override
public Object convertDataValueToObjectValue(Object dataValue, Session session) {
return dataValue;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public void initialize(DatabaseMapping mapping, Session session) {
}
}
或者,您可以尝试在 auditing example from the docs 之上构建。不过,它使用硬编码的数据库列名而不是字段级注释。
当然,使用您的数据库提供的机制(例如触发器)可能是一种性能更高的解决方案。
【讨论】:
@Convert("database-timestamp") 可以跨多个实体重用(您只能在一个实体上定义@Converter),并且preUpdate() 可以替换为@EntityListeners(不幸的是,您将需要@EntityListeners每个被审计单位)。恐怕这是最接近使用 EclipseLink 的纯基于注释的解决方案了
您可以使用CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP 获取数据库时间
【讨论】:
@Query注解中