@Entity : JPA를 사용해 테이블과 매핑할 클래스로 지정하는 어노테이션.
- 기본생성자가 반드시 필요하다.
- final, enum, interface, inner 클래스에 사용할 수 없다.
- 저장할 필드에 final을 사용할 수 없다.
- name : 기본값으로 클래스명이 사용된다. 다른 패키지에서 중복 클래스명이 엔티티로 사용된다면 충돌을 막기위해 값 설정이 필요하다.
@Table : 엔티티와 매핑할 테이블을 지정하는 어노테이션.
- name : 테이블명을 지정할 때 사용된다.(default 엔티티명)
- uniqueConstraints : DDL 생성 시에 유니크 제약조건을 만든다. 복합 유니크 제약조건도 가능하다. 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용된다.
@Table(name = "t_user", indexes = { @Index(name = "idx_u_username", columnList = "username") },
uniqueConstraints = @UniqueConstraint(name="uk_user", columnNames = {"email", "username" }))
스키마 자동 생성
- 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.
- DDL은 운영환경에서 사용할 만큼 완벽하지는 않으므로 개발 환경에서 사용하거나 매핑을 어떻게 해야하는지 참고하는 정도로만 사용한다.
- 자동 생성되는 DDL은 지정한 데이터베이스 방언에 따라 달라진다. ex) mysql : varchar, integer / oracle : varchar2, number
스키마 자동 생성 종류
create : 기존 테이블 삭제후 다시 생성. drop + create
create-drop : 위 과정에 추가로 앱 종료시 DDL 제거. drop + create + drop
update : DB 테이블과 엔티티 매핑정보를 비교해 변경사항만 수정.
validate : DB 테이블과 엔티티 매핑정보를 비교해 차이가 있으면 경고. 앱 실행X. DDL 변경X.
none : 자동생성기능 사용안함.
JPA 기본 환경설정
@Configuration
public class DataConfig {
@Autowired
private DatabaseProperties databaseProperties;
@Bean
public DataSource dataSoure(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseProperties.getDriver());
dataSource.setUrl(databaseProperties.getUrl());
dataSource.setUsername(databaseProperties.getUsername());
dataSource.setPassword(databaseProperties.getPassword());
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSoure());
factoryBean.setPackagesToScan("com.example.model");
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
// JPA 상세설정
Properties jpaProperties = new Properties();
jpaProperties.put(AvailableSettings.SHOW_SQL, true); // SQL 보기
jpaProperties.put(AvailableSettings.FORMAT_SQL, true); // SQL 포맷팅하기
jpaProperties.put(AvailableSettings.USE_SQL_COMMENTS, true); // SQL 코멘트 보기
jpaProperties.put(AvailableSettings.HBM2DDL_AUTO, databaseProperties.getHbm2ddlAuto()); // DDL 자동생성 종류
jpaProperties.put(AvailableSettings.DIALECT, databaseProperties.getDialect()); // 방언 설정
jpaProperties.put(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, true); // 키 생성 전략 사용시 설정
jpaProperties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy"); // 자바의 카멜 표기법을 테이블의 언더스코어 표기법으로 매핑
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
}
기본키 매핑
- 직접 할당 : @Id & Setter
Board board = new board(); board.setId("id1"); em.persist(board); // @Id로 지정한 id 필드에 Set메소드로 직접 할당하는 방법
- 자동 생성 : 대리키 사용 방식. @GeneratedValue
영속성 컨텍스트는 엔티티를 영속 상태로 만드려면 식별자 값이 반드시 있어야 한다.
@Id, @GeneratedValue(strategy = GenerationType.매핑전략, generator = 식별자 생성기 이름)
GenerationType.IDENTITY
- 기본키 생성을 DB에 위임하는 전략.
- DB 종속적. Mysql, PostgreSQL, SQL SERVER
- DB 저장시 @Id 컬럼을 비워두면 DB가 순서대로 값을 채워준다.
- 전략 사용시 JPA는 기본키 값을 얻어오기 위해 DB를 추가로 조회한다.
- statement.getGerenatedkey() 사용하면 데이터를 저장하면서 동시에 기본키 값을 얻어와서 DB를 한번만 조회한다.
- 트렌잭션을 지원하는 쓰기 지연이 동작하지 않는다.
GenerationType.SEQUENCE
- DB 시퀀스를 사용해 기본키를 할당한다.
- DB 종속적. Oracle, H2, DB2
- 엔티티나 컬럼에 @SequenceGenerator 표기
- name : 식별자 생성기 이름
- sequenceName : DB 시퀀스명
- initialValue : 시퀀스 시작 값 (default 1)
- allocationSize : 시퀀스 호출 시 증가 수 (default 50)
- DB 시퀀스를 사용해 식별자를 조회해 엔티티에 할당 후, 엔티티를 영속성 컨텍스트에 저장하고 트랜잭션을 커밋하면 DB에 저장된다.
GenerationType.TABLE
- 엔티티에 @TableGenerator 표기
- name : 식별자 생성기 이름 (필수)
- table : 키 생성 테이블명
- pkColumnName : 시퀀스 컬럼명
- valueColumnName : 시퀀스 값 컬럼명
- 키 생성 전용 테이블 만들고 이름과 같은 값으로 사용할 컬럼을 생성한다.
- 내부 동작은 SEQUENCE와 같다.
Sequence 테이블 생성 DDL
CREATE TABLE MY_SEQUENCE{
SEQUENCE_NAME VARCHAR(255) NOT NULL,
NEXT_VAL BIGINT,
PRIMARY KEY (SEQUENCE_NAME)
}
TABLE 전략 매핑 코드
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCE",
pkColumnValue = "BOARD_SEQ",
allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
}
GenerationType.AUTO
- DB 방언에 따라 위의 전략 중 하나를 자동으로 선택한다. ex) MySQL : IDENTITY
- DB 변경시 코드를 수정할 필요가 없다.
- SEQUENCE 전략이 사용되면 하이버네이트가 기본값을 사용해서 적절한 시퀀스를 만들어준다.
권장 식별자 선택 전략
- 기본키 조건 : NOT NULL, 유일 값, 불변
- 기본키 선택전략
- 자연키 : 비즈니스에 의미가 있는 키. ex) email, 주민등록번호 등
- 대리키(대체키) : 비즈니스에 무관한 임의의 키. ex) uuid, sequence, auto_increment 등
필드와 컬럼 매핑
@Column : 객체 필드를 테이블 컬럼과 매핑시킨다.
- name(default 필드명) : 필드와 매핑할 컬럼명
- nullable(default true) : null 허용 여부.
- unique(default false) : 컬럼에 유일값 허용 여부.
- length(default 255) : 문자길이 제약조건. String 필드에만 사용한다.
- columnDefinition : 직접 정의 "varchar(10) default 'test'". 사용하는 DB 종류에 종속될 수 있으므로 지양한다.
- insertable,updatable(default true) : 읽기전용시 false로 설정하여 DB에 저장/수정이 불가하도록 지정한다.자바 기본(primitive)타입에 @Column을 사용하면 nullable = false로 지정하는 것이 안전하다.
@Enumerated : 열거 타입 매핑
- EnumType.ORDINAL(default) - enum 순서를 DB에 저장하기 때문에 순서가 변경될 경우 안전하지 못하다.
- EnumType.STRING - enum 이름을 DB에 저장하기 때문에 안전하다.
@Temporal : 날짜 타입 매핑
- TemporalType.DATE > 2013-10-11
- TemporalType.TIME > 11:11:11
- TemporalType.TIMESTAMP(default) > 2013-10-11 11:11:11
@Lob : CLOB,BLOB 타입 매핑
- CLOB : 문자. String, char[], CLOB (mysql : longtext / oracle : clob)
- BLOB : 나머지. byte[], BLOB (mysql : longblob / oracle : blob)
@Transient : 특정 필드 매핑 제외
- 컬럼과 매핑하지 않으므로 DB에 저장하지 않는다.
- 객체 필드에 임시로 데이터를 보관하는 용도. ex) 비밀번호/확인비밀번호 값을 객체 필드로 각각 입력받아 동일한 값인지 확인
@Access : JPA가 엔티티에 접근하는 방식 지정. @Id 대체
- AccessType.FIELD : 필드에 직접 접근한다. 필드 접근 권한이 private 이어도 접근이 가능하다.
AccessType.PROPERTY : 접근자 Getter를 사용해 접근한다.
@Id가 필드에 있냐 프로퍼티에 있냐에 따라 access 방식이 달라진다.AccessType이 FIELD로 정의된 경우 영속화 과정에서 필드에 데이터를 설정하거나 읽어올 때,
메소드를 통하지 않고 직접 필드에 접근해서 읽어오기 때문에 Get/Set 메소드에 별도의 로직이 존재하는 경우 동작하지 않는다.- 반대로 필드명과 Get메소드의 이름이 다를 때, 별도의 로직을 통해 변환된 값을 DB에 저장하고 싶다면@Transient 어노테이션을 필드에 부여해 영속화에서 제외시키고 Get메소드에 @Access(AccessType.PROPERTY)를 설정하면 된다.
@Entity
public class Member {
@Id
private String id;
@Transient
private String firstName;
@Transient
private String lastName;
@Access(AccessType.PROPERTY)
public String getFullName(){
return this.firstName + this.lastName;
}
}
// @Id가 필드에 있으므로 필드 접근 방식을 사용하고 getFullName만 프로퍼티를 사용한다.
// Member 엔티티에 fullName 컬럼이 생성되고 firstName + lastName의 결과가 저장된다.
참고서적 - 자바 ORM 표준 JPA 프로그래밍 (김영한)
'Development > JPA' 카테고리의 다른 글
영속성 관리 (0) | 2017.01.21 |
---|---|
JPA 시작 (0) | 2016.11.20 |
JPA 소개 (0) | 2016.05.04 |