JPA에서 가장 중요한 두가지
- 객체와 관계형 데이터 베이스 매핑하기 (설계,정적)
- 영속성 컨텍스트 (실제 동작)
우선 영속성 컨텍스트에 대해 알아보자
"엔티티를 영구 저장하는 환경"
논리적인 개념으로 눈에 보이지 않는다.
엔티티 매니저를 통해 영속성 컨텍스트에 접근할 수 있다.
>> persist 메서드는 DB에 저장하는것이 아니라 엔티티를 영속성 컨텍스트라는곳에 저장한다는것
[ 엔티티의 생명주기 ]
· 비영속 ( new / transient )
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
· 영속 ( managed )
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// 객체를 저장한 상태(영속)
em.persist(member);
>> 이때는 DB에 저장되는것이 아니다.
· 준영속 ( datach )
em.detach(member);
회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
· 비영속 ( remove )
em.remove(member);
객체를 삭제한 상태
영속성 컨텍스트를 사용할때의 이점 !
- 지연 로딩 (Lazy Loading)
>> 이후에 공부
- 엔티티 조회, 1차 캐시
1차캐시를 보니까 member Entity가 있다. 그럼 캐시값 조회
1차 캐시에 원하는 값이 없다? 그럼 DB로 넘어가서 조회해서 값 가져온다 > 1차 캐시에 값 저장하고
반환해준다.
- 영속 엔티티의 동일성 보장
1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을
DB가 아닌 애플리케이션 차원에서 제공해준다.
- 트랜잭션을 지원하는 쓰기 지연 (transaction write-behind)
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // 엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
em.persist(memberA);
em.persist(memberB);
// 여기까지 Insert SQL을 DB에 보내지 않는다.
// 커밋하는 순간 DB에 Insert SQL을 보낸다
transaction.commit();
- 변경 감지 (Dirty Checking)
트랜잭션 시작후, 아래와 같이 값을 수정한다고 했을때
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
tracsaction.commit();
중간에 em.update(member) 같은 코드가 들어가야 값이 수정될것같은데,
그런 코드가 없어도 SQL 에서는 Update가 된다.
또한 엔티티변경시 em.persist 호출도 안한다.
왜냐면 JPA의 특징인 플러시 때문이다.
플러시는 영속성 컨텍스트의 변경내용을 DB에 반영해준다.
플러시가 발생하면
변경감지 >> 수정된 엔티티 쓰기 지연 SQL 저장소에 등록 >> 쓰기 지연 SQL 저장소의 쿼리를 데이터 베이스에 전송(등록, 수정, 삭제 쿼리)
영속성 컨텍스트를 플러시 하는 방법 (사실 자동으로 호출되기 때문에 굳이 알 필요는 없지만, 테스트시 필요)
- em.flush() : 강제로 직접 호출
(플러시를 한다고 1차 캐시를 지우는것은 아니다. 쓰기지연 SQL 저장소에 업데이트 쿼리들이 반영되는것 뿐)
- 트랜잭션 커밋 : 플러시 자동 호출
- JPQL 쿼리 실행 : 플러시 자동 호출
[ 준영속 상태 ]
영속 상태의 엔티티가 영속성 컨텍스트에서 분리( detach)
영속성 컨텍스트가 제공하는 기능을 사용 못한다.
· em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
· em.clear() : 영속성 컨텍스트를 완전히 초기화
· em.close() : 영속성 컨텍스트를 종료
JPA의 중요한 두가지 중, 이번엔 매핑에 대해 알아보자
엔티티 매핑
· 객체와 테이블 매핑 : @Entity, @Table
· 필드와 컬럼 매핑 : @Column
· 기본 키 매핑 : @Id
· 연관관계 매핑 : @ManyToOne, @JoinColumn
[ 객체와 테이블 매핑 ]
@Entity 가 붙은 클래스는 JPA가 관리하는 엔티티 라고 한다.
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수이다.
※ 주의해야할점
- 기본 생성자는 필수( 파라미터가 없는 public 또는 protected 생성자 )
- final 클래스 ,enum, interface, inner 클래스에는 사용하지 못한다.
- 저장할 필드에 final을 사용할 수 없다.
@Entity 속성 : name
· JPA 에서 사용할 엔티티 이름을 지정한다.
· 기본값 : 클래스 이름을 그대로 사용
· 같은 클래스 이름이 없으면 가급적 기본값을 사용한다.
@Entity(name="Member")
public class Member{
· · ·
}
@Table
table은 엔티티와 매핑할 테이블을 지정한다.
속성 | 기능 | 기본값 |
name | 매핑할 테이블 이름 | 엔티티 이름을 사용 |
catalog | 데이터베이스 catalog 매핑 | |
schema | 데이터베이스 schema 매핑 | |
uniqueConstraints (DDL) |
DDL 생성 시에 유니크 제약 조건 생성 |
/* name */
@Entity
@Table(name="MBR")
public class Member{
· · ·
}
DDL 생성 기능
· 제약조건 추가
ex ) 회원이름은 필수, 10자 초과X
@Column(nullable = false, length=10)
· 유니크 제약 조건 추가
@Table(uniqueConstraints ={@UniqueConstraint(name="NAME_AGE_UNIQUE",columnNames={"NAME","AGE"})})
· DDB 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
데이터베이스 스키마 자동생성
DDL을 애플리케이션 실행 시점에 자동 생성
테이블 중심 -> 객체 중심
데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL 생성 > 이렇게 생성된 DDL은 개발 장비에서만 사용 !!!!
persistance.xml 에 추가해준다.
hibernate.hbm2ddl.auto
create : 기존 테이블 삭제 후 다시 생성 (DROP + CREATE )
create - drop : 종료시점에 테이블을 DROP
update : 변경분만 반영
validate : 엔티티와 테이블이 정상 매핑되었는지만 확인
none : 사용하지 않는다.
※ 주의
운영 장비에는 절대 create, create-drop, update 를 사용하면 안된다.
스테이징 운영 서버는 validate 또는 none을 사용한다.
[ 필드와 컬럼 매핑 ]
예시를 들어 보자
요구사항
1. 회원은 일반 회원과 관리자로 구분해야 한다.
2. 회원 가입일과 수정일이 있어야 한다.
3. 회원을 설명할 수 있는 필드가 있어야 한다. 이 필드는 길이 제 한이 없다
package hellojpa;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
@Entity
public class Member {
@Id
private Long id;
@Column(name = "name")
private String username;
private Integer age;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
//Getter, Setter…
}
매핑 어노테이션 정리
@Column : 컬럼 매핑
@Temporal : 날짜 타입 매핑 (date, time, timestamp 세가지 타입이 있다)
@Enumerated : enum 타입 매핑
@Lob : BLOB, CLOB 매핑 (varchar를 넘어서 더 큰 값을 쓰고싶을때 Lob을 사용. 문자는 CLOB 나머지는 BLOB)
@Transient : 특정 필드를 컬럼에 매핑하지 않음(매핑 무시)
@Column
name : 필드와 매핑할 테이블의 컬럼 이름 (기본값 : 객체의 필드 이름)
insertable, updatable : 등록, 변경 가능 여부 (기본값: TRUE)
nullable(DDL) : null값의 허용 여부를 설정, false로 설정하면 DDL 생성시에 not null 제약조건이 붙는다.
unique(DDL) : 하나의 컬럼에 간단히 유니크 제약조건을 걸때 사용.
(사용할경우 이름이 랜덤값으로 사용하기 어려워서, @Table(uniqueConstaints = " ") 를 사용해준다.
columnDefinition : 컬럼 정보를 직접 줄 수 있다. ex) varchar(100) default 'EMPTY'
length(DDL) :문자 길이 제약조건, String 타임에만 사용 (기본값: 255)
precision, scale(DDL) : 소수점 관련 속성
@Enumereted
자바 enum 타입을 매핑할 때 사용
· EnumType.ORDINAL : enum 순서를 데이터베이스에 저장 (기본값)
· EnumType.STRING : enum 이름을 데이터베이스에 저장
※ 주의 ORDINAL 사용 X
>> enum에 값을 추가할경우 다른 값인데 순서때문에 DB에 저장된 값이 중복될 수 있다.
그냥 STRING 으로 직관적으로 만들어버리자
@Temporal
자바8부터는 LocalDate, LocalDateTime 기능을 지원해서 간단
@Transient
필드매핑 X
데이터베이스에 저장 X, 조회X
주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을때 사용한다.
@Transient
private Integer temp;
[ 기본 키 매핑 ]
기본키 매핑 어노테이션
@Id
@GeneratedValue
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
기본 키 매핑 방법
· 직접 할당 : @Id 만 사용
· 자동 생성 (@GeneratedValue)
- IDENTITY : 데이터베이스에 위임, MYSQL
AUTO_INCREMENT
JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행
AUTO_INCREMENT는 데이터베이스에 INSERT SQL을 실행 한 이후에 ID 값을 알 수 있다.
em.persist() 시점에 즉시 INSERT SQL 실행 하고 DB에서 식별자를 조회한다.
- SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용, ORACLE
@Entity
@SequenceGenerator(name="member_seq_generation", sequenceName="member_seq")
시퀀스를 쓸때 자료형을 뭘하면 좋을까?!
>> int는 0 이있어서 패스 Integer는 10억 넘어가면 한바퀴돌기때문에 패스, 결론적으로 Long을 쓰는게 베스트
- TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용
장점 : 모든 데이터베이스에 적용 가능
단점 : 성능이 좀 떨어질 수..
TableGenerator 속성 전략
- AUTO : 방언에 따라 자동 지정, 기본값
권장하는 식별자 전략
· 기본키 제약 조건 : null 아님, 유일, 변하면 안된다 (먼 미래까지 )
· 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자
· 주민등록번호도 기본키로 적절하지 않다.
권장 : Long 형 + 대체키 + 키 생성전략 사용
'spring boot > JPA' 카테고리의 다른 글
[ JPA ] 상품 / 주문 도메인 개발 (1) | 2023.12.27 |
---|---|
[ JPA ] 회원 도메인 개발 (0) | 2023.12.27 |
[ JPA ] 엔티티 클래스 개발 (0) | 2023.12.14 |
[ JPA ] 도메인 분석 설계 (0) | 2023.12.13 |
[ JPA ] View 환경설정 + DB 설정 (0) | 2023.12.13 |