jpa 를 강의를 들으면서 가장 기본적인 영속성의 개념에 대해 간단하게 정리해보려고 한다.
1. 영속성 컨텍스트란 무엇인가?
데이터 베이스와 객체 사이에 중간 단계가 있는 개념이라고 할 수 있다.
객체를 데이터베이스로 옮기거나, 데이터베이스에 있는 데이터를 객체에 매핑할 때 중간에 존재하는 저장 공간이다.
간단하게 코드로 나타내면 EntityManager.persist(entity) 로 표현할 수 있다.
이 때 이 영속성 컨텍스트가 존재함으로써 일종의 버퍼링 기능을 수행하게 되는데
persistence.xml 파일에
<property name="hibernate.jdbc.batch_size" value="10" />
를 추가하여 버퍼 사이즈를 조율할 수 있다.
버퍼링 기능을 사용하면 쿼리를 일일히 데이터베이스에 날리는게 아니라 지정한 버퍼 크기만큼 쌓아놨다가 한번에 데이터베이스에 요청하여 커밋할 수 있다.
JPA 실제 사용시 transaction commit 시점에 데이터베이스에 반영 되는 것을 염두에 두어야 한다. EntityManager.psersist(entity) 를 사용하여
영속성을 부여하더라도 데이터베이스에는 반영 되지 않는다.
위 내용을 기반으로 신규 엔티티를 생성하고 영속성을 부여하는 간단한 코드를 작성해보자.
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); // persistence.xml 에 있는 unitName 기재
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
//TestMember 생성해보기
TestMember tm = new TestMember();
em.persist(tm);
//실제 db 에 반영 되는 시점
tx.commit();
} catch(Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
여기서 생성한 Member 은 아래와 같다
@Entity
@Table(name="new_table")
public class TestMember {
private LocalDate localDate;
private LocalDateTime localDateTime;
@Lob
private String bigData;
@Enumerated(EnumType.STRING)
private TestRecord testRecord;
@Transient
private String temp;
@Id
private long realId;
... Getter/Setter ...
}
실행 결과 아래와 같은 쿼리 실행문이 실행 되면서 db 에 테이블이 생성되는 것을 확인 할 수 있다
create table new_table (
realId bigint not null,
bigData clob,
localDate date,
localDateTime timestamp,
testRecord varchar(255),
primary key (realId)
)
2. 플러시의 개념
플러시는 쌓아놨던 데이터 변경 사항들 ( 쿼리 요청들 ) 을 데이터베이스에 요청하는 개념이다.
일반적으로 transaction commit 이 발생하면 자동으로 플러시가 된다. 즉, 데이터베이스에 데이터 변경사항들이 실제로 저장 된다.
transaction commit 외에도 플러시를 발생시키는 방법은
1) jpql 요청
2) EntityManager.flush() 함수를 통한 호출
이 있다. EntityManager.flush() 는 일반적으로 사용하진 않는다.
주의 해야할 점은 플러시가 되었다고해서 1차 캐시에 담긴 내용이 삭제되는 것은 아니라는 것이다.
3. 준영속성이란?
영속성 컨텍스트에 등록된 객체(Entity) 를 영속성 컨텍스트에서 제거하는 것을 의미한다. 즉, 영속성에서 detach 된 상태를 말한다.
객체가 detach 되었다면, commit 하더라도 데이터베이스에 그 객체의 변경사항은 반영 되지 않는다.
EntityManager.detach() 를 통해 개별 객체의 영속성을 제거할 수 있다. 이 외에도
1) EntityManager.clear() : EntityManager 를 통해 등록된 모든 개체에 대해 영속성 제거
2) EntityManager.close() : EntityManager 자체를 닫아버리기 때문에 객체를 관리할 수 없음
비영속성을 확인하는 간단한 샘플코드를 작성해 보자.
Member member = new Member();
member.setId(100L);
member.setName("HelloJPA");
//영속
em.persist(member);
//비영속
em.detach(member);
tx.commit();
위 코드에서 id 가 100 이고 이름이 HelloJPA 인 객체는 db 에 반영 되었을까? 답은 아니오다. 비영속상태이기 때문이다.
4. 엔티티 매핑하기
엔티티 매핑은 총 세가지 분류로 나눌 수 있다. 객체와 테이블 , 필드와 컬럼, 연관 관계 이다.
객체와 테이블은 말그대로 객체(Entity) 와 테이블을 매핑하는 것이다. 샘플 코드를 작성해보자
@Entity
@Table(name="new_table")
public class TestMember {
...
}
@Entity 애노테이션을 통해 엔티티임을 명시하고, @Table 애노테이션을 사용하여 실제 테이블명을 지정할 수 있다.
필드와 컬럼은 클래스 내의 필드에 데이터베이스 컬럼을 매핑하는 것을 의미한다. 샘플 코드를 작성해보자
@Entity
@Table(name="new_table")
public class TestMember {
private LocalDate localDate;
private LocalDateTime localDateTime;
@Lob
private String bigData;
@Enumerated(EnumType.STRING)
private TestRecord testRecord;
@Transient
private String temp;
@Id
@Column(name = "realId")
private long realId;
... Getter/Setter ...
}
@Table 애노테이션과 동일하게 @Columm 을 통해 실제 컬럼명을 지정할 수 있다. ( 동일하다면 따로 지정하지 않아도 상관 없다.)
이 외에도 @Enumerated , @Temporal, @Lob, @Transient 애노테이션이 있는데 각각의 의미는 아래와 같다.
- @Enumerated :
enum 타입의 변수를 사용할 때 사용 한다. 주의 해야할 점은 enumType 에 ordinal 쓰면 안 된다는 것이다.
ordinal 은 enum 타입의 데이터를 순서대로 저장하게 되는데 나중에 데이터가 변경 되었을 경우 데이터 자체의 값이 아니라 순서번호로 지정되게 되면 동일한 데이터에 대해 과거와 현재의 순서번호만 변경되어 큰 문제가 생길 수 있기 때문이다.
예시 ) 'GUEST, USER, ADMIN' 라는 entype 이 정의 되어 있다고 가정 하자.
이때 GUEST 는 0, USER 은 1, ADMIN 은 2 에 해당 한다.
시간이 지나 'TEST, GUEST, USER, ADMIN' 으로 데이터가 바뀌었을 경우 'GUEST 는 0, USER 은 1, ADMIN 은 2' 에서 GUEST 는 1, USER 은 2, ADMIN 은 3 으로 바뀌게 된다. 처음에 들어온 TEST 가 0 이 되기 때문이다.
따라서 enumType 은 무조건 string 으로 지정해서 써야한다. 사용 방법은 아래와 같다.
@Enumerated(EnumType.String)
- @Temporal :
날짜 타입 지정시 사용 한다. 요즘엔 LocalDate, LocateDateTime 타입이 JAVA 에서 제공 되기 때문에 잘 쓰지 않는다.
닐짜 데이터 타입 변수에 @Temporal 를 지정하는 대신 LocalDate, LocalDateTime 타입으로 변수를 생성만하면 알아서 매핑 되기 때문이다.
- @Lob :
대량 데이터 삽입시 사용 ( Blob, Clob) 한다.
문자면 CLob, 다른 것은 Blob 으로 매핑 ( byte 같은 것들 ) 된다.
- @Transient : db 에 반영하고 싶지 않은 변수에 대해 지정 한다. 이 애노테이션을 사용하면 데이터베이스와 연관 되지 않는다 ( ddl 자동 생성시에도 생성 되지 않음 )
'Dev > JPA' 카테고리의 다른 글
JPA 에서 연관관계의 정의 (1) | 2023.12.27 |
---|---|
JPA 에서 기본 키 매핑하기 (0) | 2023.12.26 |
JPA 에서 데이터베이스 스키마 자동생성 기능 사용하기 (0) | 2023.12.11 |
h2 초기 연결시 JdbcSQLNonTransientConnectionException 에러 해결 방법 (0) | 2023.12.06 |
h2 db 연결시 javax.xml.bind.JAXBException 오류 해결 방법 (0) | 2023.12.06 |