반응형
데이터베이스 테이블을 설계하다 보면 column이 중복되는 경우가 생각보다 많습니다.
대표적으로 등록한 사람, 등록일시, 수정한 사람, 수정일시 등이 있는데요
이것을 일일히 쓰기에는 여간 귀찮은 일이 아닙니다.
이럴 때 @MappedSuperclass를 사용하면 됩니다.
그럼 지금부터 예제 코드를 보겠습니다.
먼저, BaseTme 클래스를 생성합니다.
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTime {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
}
- @MappedSuperclass
- JPA Entity 클래스들이 BaseTime 클래스를 상속할 경우 필드들도 칼럼으로 인식하도록 합니다.
- @EntityListeners(AuditingEntityListener.class)
- BaseTime 클래스에 Auditing 기능을 포함합니다.
- 여기서 Audit는 감시하다, 감사하다라는 뜻으로 Sping Data JPA에서 CreatedUser, CreatedDate, LastModifiedUser, LastModifiedDate에 대해서 자동으로 값을 넣어주는 기능입니다.(user 정보는 별도 설정을 해야 합니다.)
- @CreatedDate
- Enity가 생성되어 저장될 때 시간이 자동 저장됩니다.
- @LastModifiedDate
- 조회한 Entity의 값을 변경할 때 시간이 자동 저장됩니다.
그다음 TbUser 테이블에 BaseTime 클래스를 상속합니다.
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Getter
@Setter
@Entity
public class TbUser extends BaseTime {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long userSeq;
private String userId;
private Integer age;
}
- @GenerationType.AUTO
- PK 생성 전략을 자동으로 설정합니다.
- PK 생성 전략은 IDENTITY, SEQUENCE, TABLE, AUTO 총 네 가지가 있는데, AUTO는 상황에 따라(데이터베이스에 따라) IDENTITY, SEQUENCE, TABLE 중 하나를 선택하게 됩니다.
- spring.jpa.hibernate.use-new-id-generator-mappings=false인 경우 사용하는 DB(Dialect)에 의해 Generator가 결정됩니다.
- Dialect에서 supportsIdentityColumns()가 true 인 경우 IdentityGenerator를 사용하게 됩니다.
- false 인 경우 SequenceStyleGenerator를 사용하게 됩니다.
- 즉, IDENTITY를 지원하지 않는 Oracle의 경우 SEQUENCE 전략을 사용하게 됩니다.
- spring.jpa.hibernate.use-new-id-generator-mappings=true인 경우 Sequence 기능을 지원하는 경우 SequenceGenerator를 사용하고, Sequence 기능을 사용하지 않는 경우 TableGenerator를 사용합니다.
JPA 테스트를 위해 TbUserRepository 인터페이스를 생성합니다.
import org.springframework.data.jpa.repository.JpaRepository;
public interface TbUserRepository extends JpaRepository<TbUser, Long> {
}
마지막으로 JPA Auditing을 사용할 수 있도록 Application 클래스에 @EnableJpaAuditing 어노테이션을 추가합니다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
테스트 코드로 확인해보기
import com.example.demo.domain.TbUser;
import com.example.demo.domain.TbUserRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Optional;
@SpringBootTest
class DemoApplicationTests {
@Autowired
TbUserRepository repository;
@Test
void contextLoads() {
TbUser user = new TbUser();
user.setUserId("noroo");
user.setAge(20);
repository.save(user);
Optional<TbUser> noroo = repository.findById(user.getUserSeq());
Assertions.assertEquals(user.getAge(), noroo.get().getAge());
}
}
위 테스트 코드는 등록한 사용자의 나이와 실제 데이터베이스에 insert 된 나이를 비교하는 코드입니다.
테스트를 실행하면 아래와 같이 성공 표시가 되고 로그가 올라온 것을 볼 수 있습니다.
Hibernate: select nextval(hibernate_sequence)
Hibernate: insert into tb_user (created_date, modified_date, age, user_id, user_seq) values (?, ?, ?, ?, ?)
Hibernate: select tbuser0_.user_seq as user_seq1_0_0_, tbuser0_.created_date as created_2_0_0_, tbuser0_.modified_date as modified3_0_0_, tbuser0_.age as age4_0_0_, tbuser0_.user_id as user_id5_0_0_ from tb_user tbuser0_ where tbuser0_.user_seq=?
그다음 TB_USER 테이블을 확인하면 아래와 같이 현재 시간이 잘 들어갔다는 것을 확인할 수 있습니다.
- @LastModifiedDate 어노테이션이 적용된 칼럼에서 별도의 처리를 하지 않으면 insert 될 때 @LastModifiedDate가 적용된 칼럼도 현재 시간이 insert 됩니다.
- 하지만 update 될 때는 @CreatedDate는 업데이트되지 않으니 걱정하지 않으셔도 됩니다.
728x90
반응형
'Database ( DB ) > JPA, Querydsl' 카테고리의 다른 글
QueryDSL - order by count as alias (2) | 2022.03.01 |
---|---|
[querydsl] Executing an update/delete query (0) | 2022.01.05 |
Spring boot JPA에서 DB 예약어를 column으로 사용하는 방법 (0) | 2021.03.07 |
Spring JPA selecting specific columns (0) | 2020.12.20 |
No identifier specified for entity (0) | 2020.12.19 |