Hibernate 및 MySQL을 사용한 생성 타임 스탬프 및 마지막 업데이트 타임 스탬프
특정 최대 절전 모드 엔터티의 경우 생성 시간과 마지막 업데이트 시간을 저장해야합니다. 이것을 어떻게 설계 하시겠습니까?
데이터베이스에서 어떤 데이터 유형을 사용 하시겠습니까 (MySQL, 아마도 다른 시간대의 JVM이라고 가정)? 데이터 유형이 시간대를 인식합니까?
당신이 자바에서 어떤 데이터 유형을 사용 (
Date
,Calendar
,long
, ...)?타임 스탬프 (데이터베이스, ORM 프레임 워크 (Hibernate) 또는 응용 프로그램 프로그래머)를 설정하는 담당자는 누구입니까?
매핑에 어떤 주석을 사용
@Temporal
하시겠습니까 (예 :) ?
나는 작업 솔루션을 찾고있을뿐만 아니라 안전하고 잘 설계된 솔루션을 찾고 있습니다.
JPA 주석을 사용하는 경우 이벤트 후크를 사용 @PrePersist
하여 다음을 수행 할 수 있습니다 @PreUpdate
.
@Entity
@Table(name = "entities")
public class Entity {
...
private Date created;
private Date updated;
@PrePersist
protected void onCreate() {
created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
또는 @EntityListener
클래스 에서 주석을 사용하고 이벤트 코드를 외부 클래스에 배치 할 수 있습니다 .
당신은 사용할 수 있습니다 @CreationTimestamp
및 @UpdateTimestamp
:
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "create_date")
private Date createDate;
@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "modify_date")
private Date modifyDate;
다른 게시물에서 왼쪽과 오른쪽으로 가져온 정보와 함께이 게시물의 리소스를 가져 와서이 우아한 솔루션과 함께 다음과 같은 추상 클래스를 만듭니다.
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@MappedSuperclass
public abstract class AbstractTimestampEntity {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created", nullable = false)
private Date created;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated", nullable = false)
private Date updated;
@PrePersist
protected void onCreate() {
updated = created = new Date();
}
@PreUpdate
protected void onUpdate() {
updated = new Date();
}
}
다음과 같이 모든 엔티티를 확장하십시오.
@Entity
@Table(name = "campaign")
public class Campaign extends AbstractTimestampEntity implements Serializable {
...
}
인터셉터를 사용하여 값을 설정할 수도 있습니다
엔티티가 구현하는 TimeStamped라는 인터페이스를 작성하십시오.
public interface TimeStamped {
public Date getCreatedDate();
public void setCreatedDate(Date createdDate);
public Date getLastUpdated();
public void setLastUpdated(Date lastUpdatedDate);
}
인터셉터 정의
public class TimeStampInterceptor extends EmptyInterceptor {
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] types) {
if (entity instanceof TimeStamped) {
int indexOf = ArrayUtils.indexOf(propertyNames, "lastUpdated");
currentState[indexOf] = new Date();
return true;
}
return false;
}
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof TimeStamped) {
int indexOf = ArrayUtils.indexOf(propertyNames, "createdDate");
state[indexOf] = new Date();
return true;
}
return false;
}
}
그리고 세션 팩토리에 등록하십시오
Olivier의 솔루션을 사용하면 업데이트 문 중에 다음이 발생할 수 있습니다.
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException : 'created'열은 null 일 수 없습니다.
이 문제를 해결하려면 "작성된"속성의 @Column 주석에 updatable = false를 추가하십시오.
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created", nullable = false, updatable=false)
private Date created;
도와 주신 모든 분들께 감사드립니다. 나 자신에게 약간의 연구를 한 후에 (나는 질문을 한 사람이다), 여기 내가 가장 이해하는 것이 있습니다.
데이터베이스 열 유형 : 1970 년 이후의 시간대에 관계없이 밀리 초
decimal(20)
는 2 ^ 64에 20 자리가 있고 디스크 공간이 저렴하기 때문에 나타납니다 . 솔직 해지자 또한,DEFAULT CURRENT_TIMESTAMP
트리거도 사용하지 않습니다. 나는 DB에서 마술을 원하지 않는다.Java 필드 유형 :
long
. 유닉스 타임 스탬프는 다양한 라이브러리에서 잘 지원되고long
Y2038 문제가 없으며 타임 스탬프 산술이 빠르고 쉽습니다 (주로 연산자<
와 연산자+
는 일 / 월 / 년이 계산에 관여하지 않는다고 가정). 그리고 가장 중요한 것은, 프리미티브long
와java.lang.Long
s 모두 s와 달리 불변 이며 (가치에 의해 효과적으로 전달됨)java.util.Date
;foo.getLastUpdate().setTime(System.currentTimeMillis())
다른 사람의 코드를 디버깅 할 때 와 같은 것을 찾기 위해 정말로 화가 났을 것 입니다.ORM 프레임 워크는 데이터를 자동으로 채울 책임이 있습니다.
나는 이것을 아직 테스트하지는 않았지만 내가 할 것이라고 생각하는 문서 만보 고있다
@Temporal
.@Version
이 목적으로 사용할 수 있는지 확실하지 않습니다 .@PrePersist
및@PreUpdate
수동으로 제어하는 좋은 대안이다. 모든 엔티티에 대한 레이어 슈퍼 타입 (공통 기본 클래스)에 그 추가, 당신이 정말로 위해 타임 스탬프를 원하는 귀여운 아이디어가 제공되며 모든 당신의 엔티티.
세션 API를 사용하는 경우이 답변 에 따라 PrePersist 및 PreUpdate 콜백이 작동하지 않습니다 .
내 코드에서 Hibernate Session의 persist () 메소드를 사용하고 있으므로이 작업을 수행 할 수있는 유일한 방법은 아래 코드를 사용 하고이 블로그 게시물 ( 답변에 게시 됨)을 따르는 것 입니다.
@MappedSuperclass
public abstract class AbstractTimestampEntity {
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created")
private Date created=new Date();
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "updated")
@Version
private Date updated;
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
}
이제 @CreatedDate 및 @LastModifiedDate 주석도 있습니다.
(봄 프레임 워크)
좋은 접근 방식은 모든 엔티티에 공통 기본 클래스를 사용하는 것입니다. 이 기본 클래스에서는 모든 엔티티 (공통 디자인), 작성 및 최종 업데이트 날짜 특성에 공통적으로 이름이 지정된 경우 id 특성을 가질 수 있습니다.
작성 날짜는 단순히 java.util.Date 특성을 유지 합니다. 항상 new Date ()로 초기화하십시오 .
마지막 업데이트 필드의 경우 타임 스탬프 속성을 사용할 수 있으며 @Version으로 매핑해야합니다. 이 주석을 사용하면 Hibernate에 의해 속성이 자동으로 업데이트됩니다. 최대 절전 모드도 낙관적 잠금을 적용합니다 (좋은 일임).
강화하기 위해 : java.util.Calender
Timestamps 용이 아닙니다 . java.util.Date
시간대와 같은 지역적 요소를 무시하고 잠시 동안입니다. 대부분의 데이터베이스는 이런 방식으로 물건을 저장합니다 (보이지 않는 경우에도; 이것은 일반적으로 클라이언트 소프트웨어의 시간대 설정이며 데이터는 양호합니다)
다음 코드가 나를 위해 일했습니다.
package com.my.backend.models;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import lombok.Getter;
import lombok.Setter;
@MappedSuperclass
@Getter @Setter
public class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@CreationTimestamp
@ColumnDefault("CURRENT_TIMESTAMP")
protected Date createdAt;
@UpdateTimestamp
@ColumnDefault("CURRENT_TIMESTAMP")
protected Date updatedAt;
}
JAVA의 데이터 유형으로 java.util.Date를 사용하는 것이 좋습니다. 캘린더를 사용할 때 꽤 불쾌한 시간대 문제가 발생했습니다. 이 스레드를 참조하십시오 .
타임 스탬프를 설정하려면 AOP 방식을 사용하는 것이 좋습니다. 또는 단순히 테이블에서 트리거를 사용할 수도 있습니다 (실제로 이것이 트리거 사용이 허용되는 유일한 방법 임).
시간을 DateTime 및 UTC로 저장하는 것을 고려할 수 있습니다. MySql은 데이터를 저장하고 검색 할 때 날짜를 UTC로 변환하고 현지 시간으로 다시 변환한다는 사실 때문에 일반적으로 Timestamp 대신 DateTime을 사용합니다. 차라리 그런 종류의 논리를 한곳에 유지하고 싶습니다 (비즈니스 계층). 그래도 타임 스탬프를 사용하는 것이 바람직한 다른 상황이 있다고 확신합니다.
우리도 비슷한 상황에 처해있었습니다. 우리는 Mysql 5.7을 사용하고있었습니다.
CREATE TABLE my_table (
...
updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
이것은 우리를 위해 일했습니다.
메소드에서 @Transactional 을 사용 하는 경우 @CreationTimestamp 및 @UpdateTimestamp는 DB에 값을 저장하지만 save (...)를 사용한 후 null을 반환합니다.
이 상황에서 saveAndFlush (...)를 사용하여 트릭을 수행했습니다.
Java 코드 에서이 작업을 수행하지 않아야한다고 생각합니다 .MySql 테이블 정의에서 열 기본값을 간단히 설정할 수 있습니다.
'Programing' 카테고리의 다른 글
UIWebView가 세로로 "튀는"것을 중지 하시겠습니까? (0) | 2020.04.18 |
---|---|
Oracle SQL Developer 다중 테이블보기 (0) | 2020.04.18 |
작업 표시 줄의 텍스트를 변경하는 방법 (0) | 2020.04.18 |
moment.js로 날짜 형식 지정 (0) | 2020.04.18 |
PyPlot의 역 Y 축 (0) | 2020.04.18 |