我的实体类:
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "USER_ID_GENERATOR", sequenceName = "USER_SEQ")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_ID_GENERATOR")
@Column(name = "user_id")
private long userId;
@Temporal(TemporalType.DATE)
private Date created;
@Temporal(TemporalType.DATE)
private Date modified;
//setters and getters...
}
我希望CREATED和MODIFIED字段在您创建或修改对象时自动相互补充。 CREATED和MODIFIED字段应为TIMESTAMP类型。
我如何实现这一目标?
答案 0 :(得分:32)
在4.3使用JPA的Hibernate中,可以直接在日期字段中使用“@CreationTimestamp”和“@UpdateTimestamp”
答案 1 :(得分:17)
您只需在创建实例时创建new Date()
,然后在实体更新时更新updated
字段:
private Date created = new Date();
private Date updated = new Date();
@PreUpdate
public void setLastUpdate() { this.updated = new Date(); }
不要为这些方法中的任何一个提供setter,只提供getter。
答案 2 :(得分:13)
我们使用PreInsertEventListener和PreUpdateEventListener执行此操作:
public class TracabilityListener implements PreInsertEventListener,PreUpdateEventListener {
private void setPropertyState(Object[] propertyStates, String[] propertyNames,String propertyName,Object propertyState) {
for(int i=0;i<propertyNames.length;i++) {
if (propertyName.equals(propertyNames[i])) {
propertyStates[i]=propertyState;
return;
}
}
}
private void onInsert(Object entity,Object[] state, String[] propertyNames) {
if (entity instanceof DomainObject) {
DomainObject domainObject = (DomainObject) entity;
Date date=new Date();
domainObject.setDateCreation(date);
setPropertyState(state, propertyNames, "dateCreation", date);
domainObject.setDateModification(date);
setPropertyState(state, propertyNames, "dateModification", date);
}
}
private void onUpdate(Object entity,Object[] state, String[] propertyNames) {
if (entity instanceof DomainObject) {
DomainObject domainObject = (DomainObject) entity;
Date date=new Date();
setPropertyState(state, propertyNames, "dateCreation", domainObject.getDateCreation());
domainObject.setDateModification(date);
setPropertyState(state, propertyNames, "dateModification", date);
}
}
@Override
public boolean onPreInsert(PreInsertEvent event) {
onInsert(event.getEntity(), event.getState(), event.getPersister().getPropertyNames());
return false;
}
@Override
public boolean onPreUpdate(PreUpdateEvent event) {
onUpdate(event.getEntity(), event.getState(), event.getPersister().getPropertyNames());
return false;
}
}
但如果您希望属性为时间戳,则应使用
进行注释@Temporal(TemporalType.TIMESTAMP)
答案 3 :(得分:11)
你可以使用Spring Data JPA,Spring可以在你的字段上使用注释@CreatedBy,@ CreatedDate,@ LastModifiedBy,@ LastModifiedDate轻松实现。您可以按照以下简单示例
// Will need to enable JPA Auditing
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
class JpaConfig {
// Creating a bean of AuditorAwareImpl which will provide currently logged in user
@Bean
public AuditorAware<String> auditorAware() {
return new AuditorAwareImpl();
}
}
// Moving necessary fields to super class and providing AuditingEntityListener entity listner class
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
abstract class Auditable<U> {
@CreatedBy
protected U createdBy;
@CreatedDate
@Temporal(TIMESTAMP)
protected Date createdDate;
@LastModifiedBy
protected U lastModifiedBy;
@LastModifiedDate
@Temporal(TIMESTAMP)
protected Date lastModifiedDate;
// Getters and Setters
}
// Creating implementation of AuditorAware and override its methods to provide currently logged in user
class AuditorAwareImpl implements AuditorAware<String> {
@Override
public String getCurrentAuditor() {
return "Naresh";
// Can use Spring Security to return currently logged in user
// return ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
}
}
@Entity
class File extends Auditable<String> {
@Id
@GeneratedValue
private Integer id;
private String name;
private String content;
// Getters and Setters
}
您可以在我的文章Spring Data JPA Auditing: Saving CreatedBy, CreatedDate, LastModifiedBy, LastModifiedDate automatically上阅读更多详情。
答案 4 :(得分:2)
由于这是一个常见问题,并且通过搜索可以获得很多半生的解决方案,让我介绍一下我所确定的内容:
@CreatedDate
和@ModifiedDate
; Traceability
监听器注册实体类,如下所示。这就是你的实体类的样子:
@EntityListeners(Traceability.class)
public class MyEntity {
@CreatedDate @Temporal(TIMESTAMP) public Date created;
@ModifiedDate @Temporal(TIMESTAMP public Date modified;
....
}
这些单行定义注释:
@Retention(RUNTIME) @Target(FIELD) public @interface CreatedDate {}
@Retention(RUNTIME) @Target(FIELD) public @interface ModifiedDate {}
您可以将它们放在自己的文件中,也可以将它们放在一些现有的类中。我更喜欢前者,所以我得到了一个更清洁的完全合格的名字。
这是Entity监听器类:
public class Traceability
{
private final ConcurrentMap<Class<?>, TracedFields> fieldCache = new ConcurrentHashMap<>();
@PrePersist
public void prePersist(Object o) { touchFields(o, true); }
@PreUpdate
public void preUpdate(Object o) { touchFields(o, false); }
private void touchFields(Object o, boolean creation) {
final Date now = new Date();
final Consumer<? super Field> touch = f -> uncheckRun(() -> f.set(o, now));
final TracedFields tf = resolveFields(o);
if (creation) tf.created.ifPresent(touch);
tf.modified.ifPresent(touch);
}
private TracedFields resolveFields(Object o) {
return fieldCache.computeIfAbsent(o.getClass(), c -> {
Field created = null, modified = null;
for (Field f : c.getFields()) {
if (f.isAnnotationPresent(CreatedDate.class)) created = f;
else if (f.isAnnotationPresent(ModifiedDate.class)) modified = f;
if (created != null && modified != null) break;
}
return new TracedFields(created, modified);
});
}
private static class TracedFields {
public final Optional<Field> created, modified;
public TracedFields(Field created, Field modified) {
this.created = Optional.ofNullable(created);
this.modified = Optional.ofNullable(modified);
}
}
// Java's ill-conceived checked exceptions are even worse when combined with
// lambdas. Below is what we need to achieve "exception transparency" (ability
// to let checked exceptions escape the lambda function). This disables
// compiler's checking of exceptions thrown from the lambda, so it should be
// handled with utmost care.
public static void uncheckRun(RunnableExc r) {
try { r.run(); }
catch (Exception e) { sneakyThrow(e); }
}
public interface RunnableExc { void run() throws Exception; }
public static <T> T sneakyThrow(Throwable e) {
return Traceability.<RuntimeException, T> sneakyThrow0(e);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable, T> T sneakyThrow0(Throwable t) throws E {
throw (E) t;
}
}
最后,如果您不使用JPA但使用经典的Hibernate,则需要激活其JPA事件模型集成。这很简单,只需确保类路径包含文件META-INF/services/org.hibernate.integrator.spi.Integrator
,其内容中包含以下单行:
org.hibernate.jpa.event.spi.JpaIntegrator
通常,对于Maven项目,您只需将其放在src/main/resources
目录下。
答案 5 :(得分:2)
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
.
.
.
@CreationTimestamp
private Date created;
@UpdateTimestamp
private Date modified;
答案 6 :(得分:1)
由于在使用Hibernate Session时忽略了@PrePersist和@PreUpdate,我使用拦截器做了一个相对简单的解决方案:
定义“可审核”界面:
public interface Auditable {
public void setUpdated_at(Date date);
public void setCreated_at(Date date);
}
定义一个类“AuditableInterceptor”
public class AuditableInterceptor extends EmptyInterceptor {
private static final long serialVersionUID = -3557239720502671471L;
@override
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if (entity instanceof Auditable) {
for (int i = 0; i < propertyNames.length; i++) {
if ("updated_at".equals(propertyNames[i])) {
currentState[i] = new Date();
return true;
}
}
}
return false;
}
@override
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if (entity instanceof Auditable) {
for (int i = 0; i < propertyNames.length; i++) {
if ("created_at".equals(propertyNames[i])) {
state[i] = new Date();
return true;
}
}
}
return false;
}
}
在打开新会话时指定拦截器(您可能在实用程序类中有此功能)
sessionFactory.openSession(new AuditableInterceptor());
// sessionFactory.openSession();
在您的实体中实施Auditable接口,例如
@Entity
public class Product implements Auditable {
...
private Date created_at;
private Date updated_at;
...
public Product() {
}
...
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
public Date getUpdated_at() {
return updated_at;
} @Override
@Override
public void setUpdated_at(Date updated_at) {
this.updated_at = updated_at;
}
...
}
注意:
答案 7 :(得分:0)
最近我遇到了同样的问题,使用hibernate sessionFactory时,JPA-Annotations @PrePersist
和@PreUpdate
将无效。
使用Hibernate 5的一个简单方法是将字段声明为@Version
,每次更新数据库实例时都会正确更新实体的时间戳/ localDateTime。