JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
객체와 테이블 매핑
대표적인 엔티티 매핑
- 객체와 테이블 매핑 : @Entity, @Table
- 필드와 컬럼 매핑 : @Column
- 기본 키 매핑 : @Id
- 연관관계 매핑 : @ManyToOne, @JoinColumn
@Entity
- @Entity가 붙은 클래스는 JPA가 관리하며 엔티티라 한다.
- JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수이다.
- 주의!
- 기본 생성자가 필수(접근제한자는 public 또는 protected 생성자)
- final 클래스, enum, interface, inner 클래스 사용 불가
- 저장할 필드에 final 사용 불가
JPA는 엔티티 객체를 생성할 때 기본 생성자를 사용한다. 그러므로 기본 생성자가 필수인데.. 자바에서는 생성자가 하나도 없으면 컴파일 시 기본 생성자를 자동으로 생성한다.
public Member() { }
생성자가 하나도 없으면 기본 생성자를 자동으로 생성한다. 이 말은 생성자가 하나라도 있으면 자동 생성을 해주지 않는다는 말이기도 하다.
@Id // PK
private Long id;
private String name;
public Member() { } // 기본 생성자
public Member(Long id, String name) {
this.id = id;
this.name = name;
}
@Entity에는 name이라는 속성이 있는데 JPA에서 사용할 엔티티의 이름을 지정하며 생략 시 클래스 이름을 그대로 사용한다. name을 꼭 줘야하는 상황이 아니라면 가급적 기본값을 사용하는게 좋다.
@Entity(name = "Member")
public class Member {
}
@Table
엔티티와 매핑할 테이블을 지정한다.
- name : 매핑할 테이블 이름(기본값은 엔티티 이름)
name의 경우는 데이터베이스의 Member 테이블의 이름이 Member가 아니라 MBR이라는 이름으로 테이블이 생성되어있다면 name 속성에 그 이름을 적어주면 그 테이블과 매핑되고 쿼리가 나갈 때 FROM절에 name 속성으로 설정된 값으로 세팅된다.
@Table(name = "MBR")
// 쿼리 로그
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
MBR member0_
where
member0_.id=?
- catalog : 데이터베이스 catalog 매핑
- schema : 데이터베이스 schema 매핑
- uniqueConstraints : DDL 생성 시에 유니크 제약 조건 생성
데이터베이스 스키마 자동 생성
애플리케이션 실행 시점에 CREATE문으로 테이블을 생성을 할 수 있다. 즉, 테이블 중심이 아니라 객체 중심으로 개발을 할 수 있다. 그리고 저번 포스팅에서 JPA 특징 중 하나가 상용 DBMS별로 데이터 타입이나 함수 등의 명칭 차이를 설정만하면 알아서 맞춰주기 때문에 그에 맞는 적절한 DDL을 생성하며, 이렇게 생성된 DDL은 개발 장비에서만 사용된다. 운영 서버에서는 사용하지 않거나, 적절하게 추가적으로 다듬은 후에 사용한다.
- hibernate.hbm2ddl.auto 속성. persistence.xml에서 설정해 줄 수 있다.
- create - 기존 테이블 삭제 후 다시 생성(DROP + CREATE)
- create-drop - create와 같으나 종료 시점에 테이블을 DROP한다. (CREATE + DROP) 주로 테스트 케이스에서 많이 사용한다.
- update - 변경분만 반영한다.(운영 DB에서 사용 금지)
- validate - 엔티티와 테이블이 정상 매핑이 되었는지 확인한다.
- none - 사용하지 않는다.
- persistence.xml에서 옵션 넣기
<property name="hibernate.hbm2ddl.auto" value="속성값" />
- create 속성 시 로그
Hibernate:
drop table Member if exists
Hibernate:
create table Member (
id bigint not null,
name varchar(255),
primary key (id)
)
- create-drop 속성 시 로그
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
Hibernate:
drop table Member if exists
- update 속성 시 로그
<!--
속성을 update로 변경 후 실행해준다.
그리고 필드를 하나 추가한 후 다시 실행한다.
-->
@Id
private Long id;
private String name;
private int age; <!-- age 필드 추가 -->
<!-- update 로그 -->
Hibernate:
alter table Member
add column age integer not null
Hibernate:
select
member0_.id as id1_0_0_,
member0_.age as age2_0_0_,
member0_.name as name3_0_0_
from
Member member0_
where
member0_.id=?
<!-- drop 후 다시 생성하는 것이 아니라 alter로 테이블을 수정한다. -->
주의할 점은 필드를 추가하는 것만 인식하지 삭제하는 건 인식하지 못해서 ALTER 쿼리가 생성되지 않는다.
- validate 속성 시 로그
// 임의의 필드를 하나 추가한다.
@Id // PK
private Long id;
private String name;
private int test;
// 실행하면 test 필드가 테이블에 없다는 에러가 발생한다.
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: hello] Unable to build Hibernate SessionFactory
..생략
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing column [test] in table [Member]
..생략
- none
- 이 기능을 사용하고 싶지 않을 때의 속성값이다.
- 사실 none이 내포하고 있는 의미는 없다. 'tefdsfa'의 값을 적어도 none과 똑같이 적용된다. 즉 기능이 있는 속성 외에 다른 아무 속성을 넣으면 이 옵션이 설정되지 않는다. 참고로 주석처리를 해도 실행되지 않아 none과 똑같은 결과를 가져온다.
- 주의할 점!
- 운영 장비에는 절대 create, create-drop, update를 사용하면 안된다.
- 개발 초기 단계는 create 또는 update
- 테스트 서버는 update 또는 validate -> create를 사용하면 데이터가 다 날라가서 문제!
- 스테이징과 운영 서버는 validate 또는 none
DDL 생성 기능
- 제약 조건을 추가할 수 있다.
@Id // PK
private Long id;
@Column(nullable = false, unique = true, length = 10)
private String name;
DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA 실행 로직에는 영향을 주지 않는다.