엔티티 매핑
@Entity
- 테이블과 매핑할 클래스.
엔티티 객체를 생성할 때 기본 생성자를 사용함.
@NoArgsConstructor public class User(){ public User(String name){ } }
@Table
- 엔티티와 매핑할 테이블을 지정한다.
- name : 매핑할 테이블 이름.
- uniqueConstraints : DDL 생성 시에 유니크 제약조건을 만든다. 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용된다.
@Table(name = "mt_user", uniqueConstraints = @UniqueConstraint(name = "userid", columnNames = { "userid" })) @UniqueConstraint(columnNames={"support_room_id", "target_agent_id"})
데이터베이스 스키마 자동생성
애플리케이션 실행 시점에 db 테이블을 자동으로 생성. ddl은 운영환경에서 사용할 만큼 완벽하지는 않으므로 개발 환경에서 사용하거나 매핑을 어떻게 해야하는지 참고하는 정도로만 사용. <property name = "hibernate.hbm2ddl.auto" value="">
속성
- create 삭제후 다시생성(DROP + CREATE)
- create-drop 위와 같으나 종료 시점에 테이블 drop(DROP + CREATE + DROP) ==개발==
- update 변경분만 반영
- validate 엔티티와 매핑정보 비교해서 경고, ddl을 수정하지 않음. ==테스트 서버==
- none 옵션값을 사용하지 않으려면 속성 자체를 삭제하거나 유효하지 않은 옵션값을 주면된다.
==스테이징, 운영서버==
dev - jdbc.properties.path=classpath:jdbc.properties classpath : hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto} pom.xml : <profile> <id>env-development</id> <activation> <property> <name>target-env</name> <value>development</value> </property> </activation> <properties> <dbdrop.skip>true</dbdrop.skip> <hbm2ddl.skip>false</hbm2ddl.skip> <dbunit.skip>false</dbunit.skip> <hibernate.hbm2ddl.auto>update</hibernate.hbm2ddl.auto> ...
기본키 매핑
- 직접할당
- Board board = new board; board.setId("id1"); em.persist(board);
- 자동생성
- identity
- sequence
- table
IDENTITY
- 기본키 생성을 데이터베이스에 위임하는 전략.
- Mysql, PostgreSQL, SQL SERVER
- 데이터베이스를 저장할때 ID 컬럼을 비워두면 데이터베이스가 순서대로 값을 채워준다.
- 사용할시 jpa 는 기본 키값 얻어오기 위해 db 추가로 조회.
- @GeneratedValue strategy 속성 값을 identity로 함.
- statement.getGerenatedkey() 사용하면 데이터를 저장하면서 동시에 기본 키 값을 얻어와서 db를 한번만 조회 .
- 엔티티를 db에 저장해야 식별자 구함.
- persist 호출 즉시 insert가 db에 전달
- 트렌젝션을 지원하는 쓰기 지연이 동작하지 않는다.
SEQUENCE
- 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트.
- 시퀸스를 사용해서 기본 키를 생성.
- em.persist()를 호출할때 db 시퀸스를 사용해서 식별자를 조회
- 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장.
- 트랜잭션을 커밋해서 플러시가 일어나면 엔티티 저장.
TABLE
- @GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR")
- 키 생성 전용 테이블 만들고 이름과 같은 값으로 사용할 컬럼 생성.
- 데이터베이스 시퀀스를 흉내내는 전략.
- 내부 동작은 SEQUENCE와 같다.
AUTO
- @GeneratedValue(strategy = GenerationType.AUTO) = @GeneratedValue
- DB 방언에 따라 전략 중 하나를 자동으로 선택.
- auto를 사용할 때 SEQUENCE 전략이 사용되면 하이버네이트가 기본값을 사용해서 적절한 시퀀스를 만들어줌.
ex>
--------------------------------------------------------
-- DDL for Sequence HIBERNATE_SEQUENCE
--------------------------------------------------------
CREATE SEQUENCE "HIBERNATE_SEQUENCE"
MINVALUE 1 MAXVALUE 9999999999999999999999999999
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE ;
--------------------------------------------------------
-- DDL for Table BT_CONTACT_BOARD
--------------------------------------------------------
CREATE TABLE "BT_CONTACT_BOARD"
필드와 컬럼 매핑
1. @Colum
객체 필드 -> 테이블 컬럼 매핑
insertable T 저장시 같이 저장
updatable T 수정시 같이 수정.
nullable false not null
unique T @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용
두 컬럼 이상 사용해서 사용하려면 클래스에서 @Table.uniqueConstraints를 사용.
columnDefine ddl을 컬럼정보를 직접 줄 수 있다.
precision, scale ddl 생성 소수점
- 유니크 제약조건(uniqueConstrainsts), @Column의 length나 nullable 속성들 - ddl 을 자동으로 생성할 때만 사용되고 jpa의 실행 로직에는 영향을 주지 않는다.
2.@Enumerated
[권장] string 이름 저장 - a,b,c ordinal 순서 저장 - 0,1,2
enum RoleType { Admin, User } @Enumerated(EnumType.STRING) private RoleType roleType; member.setRoleType(RoleType.Admin);
ordinal
- 데이터베이스에 저장되는 데이터 크기가 작다.
- 이미 저장된 enum의 순서를 변경할 수 없다.
string
- 저장된 enum 순서가 바뀌거나 enum이 추가 되어도 안전하다.
- 데이터베이스에 저장되는 데이터 크기가 ORDINAL에 비해서 크다.
- ordinal을 사용했을때 enum에서 하나가 추가되면 저장된 기존 데이터때문에 String를 권장한다.
3.@Temporal - 날짜타입을 매핑할때 사용.
@Temporal(TemporalType.) DATE - date date TIME - time time TIMESTAMP - timestamp timestamp - 생략시 timestamp로 정의됨.
- timestamp 대신에 datetime을 예약어로 사용하는 데이터베이스는 방언때문에 애플리케이션 코드 변경하지 않아도됨.
- datetime : Mysql
timestamp : Oracle
@SuppressWarnings("serial") @MappedSuperclass() @Audited public abstract class BaseTimestampEntity<PK extends Serializable> extends BaseEntity<PK> { @Transient @XmlTransient @JsonIgnore private boolean disableAutoTrace; @Column(name = "updated_dt", insertable = true, updatable = true) private Date updatedDt; @Column(name = "created_dt", insertable = true, updatable = false) private Date createdDt;
ex> Oracle DDL for Table BT_CONTACT_BOARD_COMMENT_FILE CREATE TABLE "BT_CONTACT_BOARD_COMMENT_FILE" ( "COMMENT_ID" VARCHAR2(50 CHAR), "UPLOADED_FILE_ID" VARCHAR2(50 CHAR), ***** "CREATED_DT" TIMESTAMP (6), ***** "UPDATED_DT" TIMESTAMP (6), "CREATED_BY" VARCHAR2(50 CHAR), "CREATED_BY_NM" VARCHAR2(200 CHAR), "UPDATED_BY" VARCHAR2(50 CHAR), "UPDATED_BY_NM" VARCHAR2(200 CHAR) ) ;
ex> Mysql DROP TABLE IF EXISTS `bt_contact_board_comment_file`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `bt_contact_board_comment_file` ( `comment_id` varchar(50) NOT NULL, `uploaded_file_id` varchar(50) NOT NULL, ***** `created_dt` datetime DEFAULT NULL, ***** `updated_dt` datetime DEFAULT NULL, `created_by` varchar(50) DEFAULT NULL, `created_by_nm` varchar(200) DEFAULT NULL, `updated_by` varchar(50) DEFAULT NULL, `updated_by_nm` varchar(200) DEFAULT NULL, ) ;
@LOB - 필드 타입이 문자면 clob로 매핑하고 나머지는 blob로 매핑.
CLOB - String, Char[] BLOB - Byte[]
@Lob private String content; DDL for Table BT_CS CREATE TABLE "BT_CS" ( "CUSTOMER_SUPPORT_ID" VARCHAR2(50 CHAR), "CONTENT" CLOB, )
@Transient 저장하고 싶지 않은 컬럼. 임시로 어떤값을 보관하고 싶을때.
@Access 접근 방식
- @id 가 필드에 있냐 프로퍼티에 있냐에 access 방식이 달라짐.
- 필드(FIELD) 접근 : 필드에 직접 접근한다. 필드 접근 권한이 private이어도 접근 가능.
- 프로퍼티(PROPERTY) 접근 : getter를 사용한다.
ex> 필드 접근
@Entity
@Table(name="bt_cs")
@Access(AccessType.FIELD)
public class CustomerSupport extends BaseTraceableEntity<String> implements BaseSynchronizableEntity {
private static final long serialVersionUID = 2327409280108932807L;
public static final String UPLOAD_DIR = "customer_support";
@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(name="customer_support_id", length = ColumnSizeConstants.UUID)
private String id;
@Id가 필드에 있어서 @Access(AccessType.FIELD)로 설정한것과 같음. 생략 가능.