5.1 데이터 변경 시점

수년 동안 데이터베이스에 다양한 레코드를 저장할 때 두 가지 질문이 종종 발생합니다.

  • 이 항목은 언제 데이터베이스에 추가되었습니까?
  • 이 항목은 언제 마지막으로 변경되었습니까?

다음은 데이터베이스의 거의 모든 테이블에 두 개의 열이 추가되는 빈번한 작업입니다.

  • 생성_시간
  • 업데이트된 시간

첫 번째는 레코드가 생성된 날짜와 시간을 저장하고 두 번째는 마지막으로 수정된 날짜와 시간을 저장합니다. 그리고 각 Entity 클래스에는 필드가 있습니다.


@Entity
@Table(name = "entities")	
public class Entity {
  ...
 
  @Column(name="created_time")
  private Date created;
 
  @Column(name="updated_time")
  private Date updated;
}

Hibernate는 데이터베이스의 객체가 두 개의 주석 @CreationTimestamp@UpdateTimestamp.

예:

@Entity
@Table(name = "entities")
public class Entity {
  ...

	@CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "create_date")
    private Date createDate;

	@UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
	private Date modifyDate;
}

이러한 주석이 표시된 열에는 객체가 생성되고 마지막으로 수정된 정확한 시간이 항상 저장됩니다.

5.2 @PrePersist 주석

개체의 시간을 제어하기 위해 좀 더 복잡한 스크립트가 필요한 경우 Hibernate에도 이 경우에 대한 주석이 있습니다. 그들은 클래스 메서드를 표시할 수 있으며 Hibernate는 데이터베이스에 개체를 저장할 때 이러한 메서드를 호출합니다. 이러한 주석은 총 7개입니다.

@PrePersist 개체가 데이터베이스에 저장되기 전에 호출됩니다. (SQL 삽입)
@PostPersist 개체가 데이터베이스에 저장된 직후에 호출됩니다. (SQL 삽입)
@사전제거 데이터베이스에서 개체를 삭제하기 전에 호출됩니다.
@PostRemove 개체가 데이터베이스에서 삭제된 후 호출됩니다.
@사전 업데이트 데이터베이스의 개체를 업데이트(SQL UPDATE)하기 전에 호출됩니다.
@포스트업데이트 데이터베이스에서 개체의 업데이트(SQL UPDATE) 후에 호출됩니다.
@포스트로드 개체가 데이터베이스에서 로드된 후 호출됩니다.

클래스에 개체를 만들고 업데이트할 정확한 시간을 알려주는 예제를 작성해 보겠습니다.

@Entity
@Table(name = "entities")
public class Entity {
  ...

  @Column(name="created_time")
  private Date created;

  @Column(name="updated_time")
  private Date updated;

  @PrePersist
  protected void onCreate() {
    created = new Date();
  }

  @PreUpdate
  protected void onUpdate() {
  updated = new Date();
  }
}

Hibernate가 처음으로 객체를 저장하면 로 주석이 달린 메서드를 호출합니다 @PrePersist. 데이터베이스의 기존 개체를 업데이트하는 경우 주석으로 표시된 메서드를 호출합니다 @PreUpdate.

5.3 EntityListener 추가

당신이 정말로 필요하다면, Hibernate가 호출하는 객체로부터 Hibernate가 호출하는 메서드를 분리할 수 있습니다. JPA 사양을 사용하면 Entity 개체를 처리할 때 특정 시간에 호출될 수신기 클래스를 선언할 수 있습니다.

유사한 Entity 개체가 많이 있는 경우 일부를 기본 클래스로 이동하고 해당 동작을 제어하는 ​​리스너를 추가할 수 있습니다. 예:


@MappedSuperclass
public abstract class BaseEntity {
 
    private Timestamp createdOn;
 
    private Timestamp updatedOn;
 
}


@Entity
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}

그런 다음 BaseEntity 클래스에 대해 특수 리스너 클래스를 만들 수 있습니다.


public class TimeEntityListener {
 
    public void onPersist(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.createdOn = now();
    	}
    }
 
    public void onUpdate(Object entity) {
    	if (entity instanceof BaseEntity) {
        	BaseEntity baseEntity = (BaseEntity) entity;
        	baseEntity.updatedOn = now();
    	}
    }
 
    private Timestamp now() {
    	return Timestamp.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)   );
    }
}

그리고 몇 가지 주석을 사용하여 User 클래스와 해당 리스너를 연결할 수 있습니다.


@Entity
@EntityListeners(class= TimeEntityListener.class)
public class User extends BaseEntity {
 
     @Id
     private Long id;
 
     private String name;
}