Entity 와 Table 을 정확히 매핑하자.
@Entity(name = "user2")
public class User {
}
@Entity
@Table(name = "user3") // @Table 의 name 을 user3 로 지정
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
}
@Entity(name="user2") // @Table 에서 name 생략 시, @Entity 의 name 으로 테이블 이름이 지정됨
@Table
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
}
Entity 와 매핑할 Table 을 지정
name
- 매핑할 테이블 이름
- 생략시 : 엔티티 이름(@Entity(name="~") 사용
catalog : catalog 기능이 있는 DB 에서 catalog 매핑
schema : schema 기능이 있는 DB 에서 schema 매핑
uniqueContraints
- DDL 생성시 유니크 제약조건 생성
- 2개 이상의 복합 유니크 제약조건 만들 수 있음
- 스키마 자동 생성 기능을 사용해 DDL을 만들 때만 사용
특정 속성을 기본키로 설정
직접 할당
: 기본 키를 애플리케이션에서 직접 할당
@Entity(name="user2")
@Table
@Getter
@Setter
public class User {
@Id // @GeneratedValue 없이 @Id 어노테이션만 적게될 경우, 기본키값을 직접 부여해줘야 한다.
@GeneratedValue // 기본값을 DB 에서 자동 생성
private Long id;
private String name;
}
// 사용 방식
Board board = new Board(); // 객체를 생성하고
board.setId("id1") // 해당객체에 기본 키의 value값을 세팅 → 기본 키 직접 할당
em.persist(board);
자동 생성
: 대리 키 사용
@GeneratedValue(startegy = GenerationType.IDENTITY)
// 선언방식
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
// 사용 방식
private static void logic(EntityManager em) {
Board board = new Board();
em.persist(board); // Board 객체를 DB에 저장하고 (실제로는, 영속성 컨텍스트를 통해서 엔티티를 영속화)
System.out.println("board.id = " + board.getId()); // 저장된 데이터(ROW)의 새로 생성된 ID 컬럼을 가져와서 출력
}
@GeneratedValue(startegy = GenerationType.SEQUENCE)
// 선언방식
@Entity
// sequenceName 속성을 이용하여, DB에서 생성한 "BOARD_SEQ"와 매핑
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR") // BOARD_SEQ_GENERATOR라는 시퀀스 생성기를 등록
private Long id;
...
}
// 사용 방식
private static void logic(EntityManager em) {
Board board = new Board();
em.persist(board); // em.persist() 실행시, DB 시퀀스를 사용해서 ID를 조회하고, 조회한 ID를 엔티티에 세팅한 후 DB에 저장
System.out.println("board.id = " + board.getId());
}
@GeneratedValue(startegy = GenerationType.TABLE)
// 선언 방식
@Entity
// @TableGenerator를 사용해서, 테이블 키 생성기를 등록
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCES", // MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑
pkColumnValue = "BOARD_SEQ", allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "BOARD_SEQ_GENERATOR") // "BOARD_SEQ_GENERATOR" 라는 이름의 테이블 키 생성기를 등록
private Long id
// 사용 방식
private static void logic(EntityManager em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
AUTO 전략 : @GeneratedValue(startegy = GenerationType.AUTO)
// 선언 방식
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
}
@Column
private String name;
객체 필드를 테이블 컬럼과 매핑
name
- 필드와 매핑할 테이블의 컬럼 이름 지정
- default 는 필드이름으로 대체
insertable
- true : 엔티티 저장시 필드값 저장
- false : 필드값이 저장되지 않음
//Entity
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
@Id
@GeneratedValue
private Long id;
// 필드값이 저장되지 않음 -> User 엔티티의 name 컬럼에 "test"를 입력해도 DB에는 값이 들어가지 않는다.
@Column(insertable = false)
private String name;
private String age;
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = User.builder()
.age("12")
.name("test")
.build();
em.persist(user); // em.persist 로 user 호출
}
}
updatable
- true : 엔티티 수정시 값이 수정
- false : 엔티티 수정시 값이 수정 되지 않음
//Entity
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
// 엔티티 수정시 값이 수정 되지 않음 -> User 엔티티 name 컬럼에 "test"를 입력하고 "change test"로 변경해도 변경값이 적용되지 않는다.
@Column(updatable = false)
private String name;
private String age;
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = User.builder()
.age("12")
.name("test")
.build();
em.persist(user); // em.persist 로 user 호출
user.setName("change test");
}
}
table : 하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용
nullable
- null값 허용 여부 설정
- false : not null 제약 조건
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = true)
private String age;
}
unique : 컬럼에 유니크 제약조건 부여
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String name;
@Column(unique = false)
private String age;
}
columnDefinition : 데이터베이스 컬럼 정보를 직접 부여
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String name;
@Column(columnDefinition = "VARCHAR(15) NOT NULL")
private String age;
}
length
- 문자 길이 제약조건
- String 타입일 때 사용
@Entity(name="user2")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
@Column(length = 11)
private String name;
@Column(columnDefinition = "VARCHAR(15) NOT NULL")
private String age;
}
precision, scale
- BigDecimal 타입에서 사용 (Java 에서 숫자를 정밀하게 저장/표현할 수 있는 객체)
- precision : 소수점을 포함한 전체 자릿수 설정
- scale : 소수의 자릿수
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id // @Access를 설정하지 않으면, 기본키를 설정하는 @Id의 위치를 기준으로 접근 방식 설정
@GeneratedValue
private Long id;
}
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
@Access(AccessType.FIELD)
public class User {
@Id
@GeneratedValue
private Long id;
}
JPA가 엔티티 데이터에 접근하는 방식을 지정
AccessType.FILED
- 필드에 직접 접근
- 필드 접근 권한이 private여도 접근 가능
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
@Access(AccessType.FIELD)
public class User {
@Id
@GeneratedValue
private Long id;
}
AccessType.PROPERTY : getter(접근자)를 통해 접근
@Entity(name = "user2")
@Table(name = "user3")
@Setter
@Access(AccessType.PROPERTY)
public class User {
@GeneratedValue
private Long id;
// getter 에 @id 를 설정
// @Id가 getter에 위치하는 경우, @Access 생략 가능
@Id
public Long getId() {
return id;
}
}
필드 접근과 프로퍼티 접근을 혼합해서!
//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
@Transient
private String name;
// PROPERTY 를 통해, getter의 fullName을 column으로 지정
@Access(AccessType.PROPERTY)
public String getFullName() {
return name + " hello";
}
protected void setFullName(String firstName) { }
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = new User();
user.setName("aaa");
em.persist(user); // em.persist 로 user 호출
}
}
//Enum 클래스
public enum RoleType {
ADMIN, USER
}
//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@Enumerated(value = EnumType.ORDINAL) // ADMIN의 순서인 0이 저장됨
private RoleType ordinal;
@Enumerated(value = EnumType.STRING) // 문자열 자체가 저장됨
private RoleType string;
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = new User();
user.setName("test");
user.setOrdinal(RoleType.ADMIN);
user.setString(RoleType.ADMIN);
em.persist(user); // em.persist 로 user 호출
}
}
자바 enum 타입을 매핑
ADMIN, USER 사이에 enum 이 하나 추가되면, USER가 순서상 2번이 된다.
하지만 DB에서는 기존 번호 USER를 1로 저장했기 때문에 문제가 발생할 수 있으므로
되도록이면 EnumType.STRING 사용을 권장
//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@Enumerated(value = EnumType.ORDINAL)
private RoleType ordinal;
@Enumerated(value = EnumType.STRING)
private RoleType string;
@Temporal(value = TemporalType.DATE)
private Date date;
@Temporal(value = TemporalType.TIME)
private Date time;
@Temporal(value = TemporalType.TIMESTAMP)
private Date timeStamp;
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = new User();
Date date = new Date();
user.setName("test");
user.setOrdinal(RoleType.ADMIN);
user.setString(RoleType.ADMIN);
user.setTime(date);
user.setDate(date);
user.setTimeStamp(date);
em.persist(user); // em.persist 로 user 호출
}
}
날짜 타입을 매핑
실무에선 잘 사용 X
//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@Enumerated(value = EnumType.ORDINAL)
private RoleType ordinal;
@Enumerated(value = EnumType.STRING)
private RoleType string;
@Temporal(value = TemporalType.DATE)
private Date date;
@Temporal(value = TemporalType.TIME)
private Date time;
@Temporal(value = TemporalType.TIMESTAMP)
private Date timeStamp;
@Lob
private String stringLob;
@Lob
private Integer integerLob;
}
//Service
@Service
@RequiredArgsConstructor
public class TestService {
private final EntityManager em;
@Transactional
public void test() {
User user = new User();
Date date = new Date();
user.setName("test");
user.setOrdinal(RoleType.ADMIN);
user.setString(RoleType.ADMIN);
user.setTime(date);
user.setDate(date);
user.setTimeStamp(date);
user.setStringLob("hello");
user.setIntegerLob(2);
em.persist(user); // em.persist 로 user 호출
}
}
Mysql에서의 결과
integerLob 은 LONGBLOB 으로 매핑
stringLob 은 LONGTEXT 으로 매핑
필드 타입이 문자열 : CLOB
나머지 : BLOB을 매핑
실무에선 잘 사용 X
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@Enumerated(value = EnumType.ORDINAL)
private RoleType ordinal;
@Enumerated(value = EnumType.STRING)
private RoleType string;
@Temporal(value = TemporalType.DATE)
private Date date;
@Temporal(value = TemporalType.TIME)
private Date time;
@Temporal(value = TemporalType.TIMESTAMP)
private Date timeStamp;
@Lob
private String stringLob;
@Lob
private Integer integerLob;
//임시 사용
@Transient
private String trans;
}
@Transient를 단 trans필드는 DB컬럼에 추가되지 않는다.
참고: [JPA] 2. 엔티티 매핑 @어노테이션 정리/예제
참고: 4장 엔티티 매핑
참고: [Spring JPA] JPA 엔티티 매핑(Entity Mapping)