@Entity // JPA를 사용하기위해 무조건 필수
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Member {
@Id // PK
private Long id;
private String name;
}
persistence.xml
...
<property name="hibernate.hbm2ddl.auto" value="create" />
...
옵션 | 설명 |
create | 기존테이블 삭제 후 다시 생성 (DROP + CREATE) |
create-drop | create와 같으나 종료시점에 테이블 DROP |
update | 변경분만 반영(운영DB에는 사용하면 안됨) |
validate | 엔티티와 테이블이 정상 매핑되었는지만 확인 |
none | 사용하지 않음 |
• 개발 초기 단계는 create 또는 update
• 테스트 서버는 update 또는 validate
• 스테이징과 운영 서버는 validate 또는 none
> 운영 장비에는 절대 create, create-drop, update 사용하면 안된다.
DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
@Column(unique = true, length = 10)
private String name;
@Column으로 DB제약조건을 입력할수있습니다.
어노테이션 | 설명 |
@Column | 컬럼 매핑 |
@Temporal | 날짜 타입 매핑 |
@Enumerated | enum 타입 매핑 |
@Lob | BLOB, CLOB 매핑 |
@Transient | 특정 필드를 컬럼에 매핑하지 않음(매핑 무시) |
@Entity
@Getter
@Setter
public class Member {
@Id // PK 매핑
private Long id;
@Column(name = "name") // DB컬럼명은 name
private String username;
private Integer age;
@Enumerated(EnumType.STRING) // Java Enum을 매핑
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Lob
private String description;
public Member() {
}
}
name | 필드와 매핑할 테이블의 컬럼 이름 |
insertable / updatable | 해당 컬럼의 INSERT / UPDATE 여부 |
nullable | NotNull제약조건 추가 |
unique | 컬럼에 제약조건을 걸때 사용하지만, 이름이 이상하게 생성되어 사용하지않음 |
columnDefinition | 데이터베이스 컬럼 정보를 직접 줄 수 있음 |
precision | BigDecimal 타입에서 사용 |
@Enumerated(EnumType.STRING)
@Enumerated(EnumType.ORDINAL)
private RoleType roleType;
EnumType이 String과 Ordinal처럼 2개가 있는데 EnumType.ORDINAL로 설정 시 Enum의 값에 순서가 들어가 실제 데이터가 0, 1, 2...가 입력됩니다. 이때 순서가 바뀌거나 신규 추가가 발생시 순서가 꼬이는 상황이 발생되어 EnumType.STRING으로 입력해야 추후 문제가 발생하지 않게됩니다.
Member member = new Member();
member.setId(2L);
member.setUsername("B");
member.setRoleType(RoleType.ADMIN);
em.persist(member);
setRoleType처럼 값을 이력하게되면 아래에 ROLETYPE값처럼 확인 할수 있습니다.
날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용
import java.time.LocalDate;
import java.time.LocalDateTime;
...
private LocalDate localDate;
private LocalDateTime localDateTime;
위처럼 LocalDate, LocalDateTime을 사용할 때는 생략이 가능합니다.
데이터베이스 BLOB, CLOB 타입과 매핑
매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용
@Id : 직접 할당
@GeneratedValue : 자동 생성
...
@Id // PK 매핑
@GeneratedValue(strategy = GenerationType.AUTO) // 방언에 따라 자동 지정, 기본값
@GeneratedValue(strategy = GenerationType.IDENTITY) // 데이터베이스에 위임
@GeneratedValue(strategy = GenerationType.SEQUENCE) // 오라클에서 자주 사용 - DB시퀀스 오브젝트에서 사용
private Long id;
...
SEQUENCE를 사용할때는 상단에 시퀀스제네레이터를 선언해야합니다.
@Entity
@SequenceGenerator(name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1 // DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는수를 지정한다
, allocationSize = 1 // 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다
)
public class Member {
...
영속성 컨텍스트에 1차캐시에 데이터가 등록되기 위해선 PK가 있어야 하는데, IDENTITY로 전략을 하게되면 DB에 INSERT 후에 PK가 설정되게 됩니다.
위와 같은 상황이라면, PK가 없는 상태에서 INSERT가 되어야하는데 JPA와는 맞지 않는상황입니다.
그래서 JPA에서는 IDENTITY가 PK가 될때 em.persist(member); 되는 순간 INSERT 쿼리가 실행되게 됩니다(원래는 commit이 되어야지 SQL저장소에서 한번에 스크립트가 DB에 전송되었던 상황이랑 다르게됩니다.)
SEQUENCE도 IDENTITY와 비슷합니다. em.persist(member);가 되는 순간 시퀀스에 다음 값을 호출하게됩니다. 하지만 IDENTITY와 다르게 INSERT되는 것이아니라 영속성 컨텍스트에 member.setId(가져온 시퀀스값)이 바인딩 되게 됩니다. IDENTITY와 다르게 DB에는 입력이 되지 않은 상태입니다.
그후 commit()시에 flush가 되게 됩니다.
여기서 만나게 되는 의문점이있는데, 시퀀스에서 조회 후 또 INSERT를 하게되면 DB에 대한 자원낭비가 되지않나라는 의문점을 가지게됩니다. 이를 해결하기위해 @SequenceGenerator 어노테이션에allocationSize 설정값이 있습니다.
이는 미리 시퀀스에서 할당치 만큼 조회하여 가지고있는것입니다.
DB는 한번 호출 시에 이미 할당치 만큼 증가가 되어있고, 웹서버는 메모리에 쌓아두고 있는 상태입니다.