JPA
JPA기본기 다지기_필드와 컬럼 매핑
JANNNNNN
2024. 3. 22. 13:27
데이터베이스 스키마 자동으로 생성하기
- DDL을 애플리케이션 실행 시 자동으로 생성
- 테이블 중심 -> 객체 중심
- 이렇게 생성된 DDL은 개발 장비에서만 사용 (운영에서 **절대!!**하면 안됨)
- 개발과정에서는 ORM프레임워크를 사용해 개발자가 DDL을 직접 작성하지 않아도 자동으로 스키마를 생성해 테스트를 하는 것은 괜찮지만,
- 운영과정에서는 실제로 프로그램을 배포하고 실행하여 사용자가 서비스를 이용하는 것이기 때문에 자동으로 생성된 DDL을 사용하면 데이터베이스의 스키마가 변경되어 데이터 손실등 예기치 않은 문제가 발생할 수도 있기 때문.
❓DDL : Data Definition Language의 약자로, DB 스키마를 정의, 수정하는데 사용되는 SQL
ex) CREATE, ALTER, DROP, COMMENT ...
- create : DROP + CREATE
- create-drop : DROP + CREATE + DROP
- update : 변경분만 반영
- validate : 엔티티와 테이블이 정상매핑 되었는지만 확인
- none : 사용하지 않음
운영 장비에선 절대 create, create-drop, update 사용하면 안됨!!!
- 개발 초기 : create or update
- 테스트 서버 : update or validate
- 스테이징과 운영서버 : validate or none
실습 1. 스키마 자동 생성
1. persistence.xml에 다음 설정 추가2. 전에 작성한 코드 실행전에는 재실행하면 Exception이 발생했었지만, 지금은 DROP 후 CREATE을 해주기 때문에 Exception이 발생하지 않는 것과, CREATE TABLE ...의 SQL이 실행되는 것을 볼 수 있다.
4. 다시 실행새로 생성되는 Member 테이블에 age 컬럼이 추가된 것을 볼 수 있다➡️자동으로 테이블이 생성되거나 하면, 데이터가 손실되거나 잘못될 위험이 있기 때문@Entity // JPA의 객체이다! public class Member { @Id // PK값이다! private Long id; private String name; // age 값 추가 private int age; ....
- ⚠️이런 부분이 실제 운영단계에선 위험하다 !!
- 3. Member class에 age 필드를 추가해보자!
- <property name="hibernate.hbm2ddl.auto" value="create"/>


@Column
- 가장 많이 사용된다.
- name : 필드와 매핑할 테이블의 컬럼 이름
- insertable, updatatable : 읽기 전용
- nullable : null허용여부 결정, DDL생성시 사용
- unique : 유니크 제약조건, DDL생성시 사용
@Temporal
@Temporal(TemporalType.DATE)
private Date date; //날짜
@Temporal(TemporalType.TIME)
private Date time;//시간
@Temporal(TemporalType.TIMESTAMP)
private Date timestamp;//날짜와 시간
@Enumerated
- 열거형 매핑
- EnumType.ORDINAL : 순서를 저장(기본값)
- EnumType.STRING: 열거형 이름을 그대로 저장, 가급적 이것을 사용!!
@Enumerated(EnumType.STRING)
private MemberType memberType;
@Lob
- 컨텐츠의 길이가 너무 길 경우, 바이너리파일로 DB에 넣어야 하는데 이때 사용한다
- CLOB, BLOB 매핑
- CLOB : String, char[], java.sql.CLOB
- BLOB : byte[], java.sql.BLOB
- 그냥 @Lob 어노테이션을 String타입에 쓰면 CLOB이 되고, Byte타입에 쓰면 BLOB가 된다.
@Lob
private String lobString;
@Lob
private byte[] lobByte;
@Tranisent
- 이 필드는 매핑하지 않는다는 뜻이다
- 애플리케이션에더 DB에 저장하지 않는 필드
- 거의 사용하지 않는다.
식별자 Annotation
- @Id
- @GenerateValue
- 옵션
- AUTO : IDENTITY, SEQUENCE, TABLE 중 Dialect에 맞는 방식으로 자동 적용
- ex) Id값을 넣지 않아도 자동으로 할당해줌
- IDENTITY : Database에 "값을 알아서 채워줘"라는 뜻의 위임 (MySQL)
- SEQUENCE : Sequence Object 사용 (Oracle)
- TABLE : 키 생성용 테이블 사용 (모든 DB)
- AUTO : IDENTITY, SEQUENCE, TABLE 중 Dialect에 맞는 방식으로 자동 적용
- MySQL의 AutoIncrement, Oracle의 Sequence와 같은 느낌
- 옵션
- 기본키 제약조건
- Not Null
- Unique
- 불변
- 미래까지 이 조건을 만족하는 자연키는 찾기 힘듦
- 대체키를 사용하자!
- 예를 들어 주민등록번호도 기본키로 사용하기 어려움!
- 권장 : Long + 대체키 + 키 생성전략 사용
- Int type ㄴㄴ! Long type ㄱㄱ!
- or UUID 사용! -> But, 성능 문제는 확인해보고 사용
실습 2. 여러 Annotation 사용해보기
1. 위에 작성한 여러 Annotation들을 사용해보자
// 수정한 Member class
import javax.persistence.*;
import java.util.Date;
@Entity // JPA의 객체이다!
public class Member {
@Id // PK값이다!
@GeneratedValue(strategy = GenerationType.AUTO) // 키 자동 생성
private Long id;
@Column(length = 20)
private String name;
private int age;
@Temporal(TemporalType.TIMESTAMP)
private Date regDate;
// 현업에선 무조건 STRING으로 써야 함
// ORDINAL 썼을 경우 인덱스가 들어감 (0, 1, ..)
// 기본값은 ORDINAL
@Enumerated(EnumType.STRING)
private MemberType memberType;
...
// getter/setter
}
// 수정한 Main Class & method
package hellojpa;
import hellojpa.entity.Member;
import hellojpa.entity.MemberType;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.Date;
public class Main {
public static void main(String[] args) {
// 1. EntityManagerFactory 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
// 2. EntityManagerFactory를 통해 EntityManager 생성
EntityManager em = emf.createEntityManager();
// 3. EntityManager를 통해 트랜잭션 획득
EntityTransaction tx = em.getTransaction();
// 4. 트랜잭션 시작
tx.begin();
// 에러 났을 경우를 대비해 try-catch로 처리
try {
// 5. 새로 삽입할 Member 객체 생성
Member member = new Member();
member.setId(1L);
member.setName("안녕하세요");
member.setRegDate(new Date());
member.setMemberType(MemberType.USER);
// 6.EntityManager를 통해 생성한 Member 객체 저장
em.persist(member);
// 7. 트랜잭션 커밋
tx.commit();
} catch (Exception e) {
// 8. 실패하면 롤백!
tx.rollback();
} finally {
// 9. EntityManagerFactory 및 EntityManager 종료
em.close();
emf.close();
}
}
}