-
-
안녕하세요? 오늘은 JPA에서의 데이터 타입 분류에 대해서 알아보도록 하겠습니다.
JPA에서의 데이터 타입은, 엔티티 타입과, 값 타입으로 분류합니다.
엔티티 타입
: @Entity로 정의하는 객체 : 식별자가 존재 : 생명주기 관리 가능 : 공유 가능 : 데이터가 변해도,식별자로 지속해서 추적 가능 |
값 타입
: 의미있는 비지니스 메소드 생성 사용 가능 : 식별자 미존재 : 공유하지 않고, 복사해서 사용 : 불변 객체로 만들어서 사용 (getter 생성, setter 미생성) : int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체 : 복잡한 객체 세상을 단순화하기 위한 개념 > 단순하고 안전하게 다룰 수 있어야한다. >> 엔티티를 값 타입으로 만들면 X >>> 식별자가 필요하고, 지속해서 값을 추적하고, 값을 변경해야 한다면, 값 타입이 아닌 엔티티 사용 |
※ 모든 값 타입은, 생명주기를 엔티티에 의존
+
값 타입에서는 기본 값 타입 임베디드 값 타입 컬렉션 값 타입의 세가지 타입이 존재합니다.
++
기본 값 타입
(primitive type)
: 자바가 제공하는 값 세팅 기본 타입 : 생명주기를 엔티티에 의존 |
※ 값 타입은 서로 값을 공유해서는 안된다.
> 부작용 발생 (Side effect)
기본 타입 | int, double ... | 공유 불가, 값을 복사하는 개념 |
래퍼 클래스 | Integer, Long ... | 공유 가능, 주소를 참조하는 개념, 변경 불가 |
특수 클래스 | String ... |
++
임베디드 타입
(embedded type)
: 복합 값 타입 : 새로운 값 타입 직접 정의 가능 : 기본 값 타입을 모아서 생성 : int, String과 같은 값 타입 : 재사용 가능 : 높은 응집도 : 의미있는 메소드 생성 가능 : 객체와 테이블의 아주 세밀한(Find-grained) 매핑 가능 : 하나의 엔티티에서 값은 값 타입의 중복 사용 불가 > AttributeOverrides 사용으로 해결 가능 |
※ 임베디드 타입은 엔티티의 값일 뿐임을 명심
+++
사용 방법
: @Embeddedable > 값 타입을 정의하는 곳에 표시 : @Embedded > 값 타입을 사용하는 곳에 표시 : 기본 생성자 필수 |
EntityA 엔티티 생성)
@Entity
public class EntityA {
@Id @GeneretedValue
@Column(name = "ENTITYA_ID")
private Long id;
@Column(name = "ENTITYA_NAME")
private String name;
// Item1 + Item2
private LocalDateTime item1;
private LocalDateTime item2;
// Item3 + Item4
private String item3;
private String item4;
...
}
해당 EntityA 엔티티에서,
Item3 , Item4 관련 항목들을,
임베디드 타입으로 변경하게 되면 아래와 같다.
EntityA 엔티티 생성)
@Entity
public class EntityA {
@Id @GeneretedValue
@Column(name = "ENTITYA_ID")
private Long id;
@Column(name = "ENTITYA_NAME")
private String name;
// Item1 + Item2
private LocalDateTime item1;
private LocalDateTime item2;
// Item3 + Item4
@Embedded
private Item34 item34;
...
}
Item34 관련 임베디드 값 타입 생성)
@Embeddable
public class Item34 {
private String item3;
private String item4;
...
}
샘플코드)
EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Item34 item34 = new Item34( item3: "item3_1", item4: "item4_1");
EntityA entityA = new EntityA();
entityA.setName("entityA_1");
entityA.setItem34(item34);
em.persist(entityA);
tx.commit();
※ 값 타입의 실제 인스터스인 값을 공유하는것은 위험
: Side effect 발생
> 대신 값을 복사해서 사용
샘플 코드)
Item34 item34 = new Item34( item3: "Item3_1", item4: "Item4_1");
EntityA entityA1 = new EntityA();
entityA1.setName("entityA_1");
entityA1.setItem34(item34);
em.persist(entityA1);
Item34 copyItem34 = new Item34( item34.getItem3(), item34.getItem4());
EntityA entityA2 = new EntityA();
entityA2.setName("entityA_2");
entityA2.seItem34(copyItem34);
em.persist(entityA2);
tx.commit();
※ 직접 정의한 값 타입은,
자바의 기본 타입이 아니라 객체 타입
> 객체 타입은 공유 참조를 피할 수 없다.
> 불변 객체로 설계 / 생성 (getter 생성, setter 미생성)
(Immutable object)
기본 타입 (primitive type) | < - > | 객체 타입 |
기본 타입은 값을 복사 ex) int a = 10; int b = a; a = 20; -> b 값은 미변경 |
객체 타입은 참조를 전달 ex) Item34 a = new Item34("Old"); ITEM34 b = a; a.setItem3("New"); -> b 값도 New로 변경 |
++
- 컬렉션 값 타입
(collection value type)
: 추적할 필요가 없고, 데이터 수정이 필요 없는 상황에서 주로 사용 : 자바 컬렉션에, 기본 값 / 임베디드 타입을 넣어서 사용 : DB는 컬렉션을 같은 테이블에 저장 불가 > 컬렉션을 저장하기 위한 별도의 테이블 필요 : 식별자가 없고 값만 있으므로 변경시 추적이 불가 > 관련된 데이터 전부 삭제 후, 최종 데이터 등록 >> 매핑하는 테이블은 모든 컬럼을 묶어서, 기본 키를 구성해야 한다. (Not Null / 중복 X : 모든 테이블 컬럼이 PK로 사용) >>> 해당 기능 대신, 일대다 [1:N] 관계를 고려 |
※ 컬렉션 값 타입은, 영속성전이 CASCADE와 고아객체 제거 기능을 필수로 가진다.
+++
사용법
@ElementCollection
@CollectionTable
EentityA 엔티티 생성)
@Entity
public class EntityA {
@Id @GeneretedValue
@Column(name = "ENTITYA_ID")
private Long id;
@Column(name = "ENTITYA_NAME")
private String name;
@Embedded
private Item34 item34;
@ElementCollection
@CollectionTable(name = "ITEMS",
joinColumns = @JoinColumn(name = "ENTITYA_ID"))
@Column(name = "ITEM_NAME") // 예외적 허용
private Str<String> items = new HashSet<>();
@ElementCollection
@CollectionTable(name = "ITEM34_H",
joinColumns = @JoinColumn(name = "ENTITYA_ID"))
private List<Item34> item34History = new ArrayListM<>();
...
}
Items 임베디드 값 타입 생성)
: entityA 엔티티에서
ITEM_NAME 외 사용 항목이 없기 때문에,
별도 생성 불필요
ITEM34 임베디드 값 타입 생성)
@Embeddable
public class Item34 {
private String item3;
private String item4;
...
}
샘플코드)
EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Item34 item34 = new Item34(item3: "ITEM3_1", item4: "ITEM4_1");
EntityA entityA = new EntityA();
entityA.setName("entityA_1");
entityA.setItem34(item34);
entityA.getItems().add("items_1");
entityA.getItems().add("items_2");
entityA.getItems().add("items_3");
entityA.getItem34History().add(new Item34(item3: "ITEM3_2", item4: "ITEM4_2"));
entityA.getItem34History().add(new Item34(item3: "ITEM3_3", item4: "ITEM4_3"));
em.persist(entityA);
em.flush();
em.close();
EntityA findEntityA = em.find(EntityA.class, entityA.getId());
// 지연로딩
Set<String> items = findEntityA.getitems();
for (String item : items) {
System.out.println("item : " + item);
}
// 지연로딩
List<Item34> item34History = findEntityA.getItem34History();
for (Item34 item34 : item34History) {
System.out.println("item34 : " + item34.getItem34());
}
// 일부 데이터만 삭제 후 신규 등록
findEntityA.getItems().remove( o: "items_1");
findEntityA.getItems().add("items_4");
// 테이블 내용을 통채로 삭제 후 등록
findEntityA.getItem34History.remove(new Item34(item3: "ITEM3_1", item4: "ITEM4_1"));
findEntityA.getItem34History.add(new Item34(item3: "ITEM3_4", item4: "ITEM4_4"));
tx.commit();
DB 결과) ENTITYA
ENTITYA_ID | ENTITYA_NAME | ITEM3 | ITEM4 |
1 | entityA_1 | ITEM3_1 | ITEM4_1 |
DB 결과) ITEMS
ENTITYA_ID | ITEMS |
1 | items_2 |
1 | items_3 |
1 | items_4 |
DB 결과) ITEM34_H
ENTITYA_ID | ITEM3 | ITEM4 |
1 | ITEM3_2 | ITEM4_2 |
1 | ITEM3_3 | ITEM4_3 |
1 | ITEM3_4 | ITEM4_4 |
데이터 타입의 비교
: 인스턴스가 달라도,
그 안에 값이 같으면 같은것으로 봐야 함
기본 타입 | < - > | 객체 타입 |
int a = 10; int b = 10; -> a == b : true로 사용 가능 ->> 동일성 비교(identity) |
Items a = new Items("items_4"); Items b = new Items("items_4"); -> a == b : false 사용 불가 (인스턴스 자체가 다르기 때문) ->> a.equals(b) 사용 ->>> 동등성 비교(equivalence) |
오늘은 JPA에서의 데이터 타입 분류에 대해서 알아보았습니다.
그럼 오늘도 즐거운 하루 되시길 바라겠습니다.
'프로그래밍 > Back-end' 카테고리의 다른 글
JPA 영속성 영속상태와 준영속상태 (0) | 2024.10.15 |
---|---|
JPA 영속성 Flush (0) | 2024.10.15 |
JPA 영속성 컨텍스트의 장점에 대하여! (0) | 2024.10.15 |
JPA 영속성과 영속성 컨텍스트에 대하여! (0) | 2024.10.15 |
JPA 키 매핑 종류와 전략에 대해서! (0) | 2024.10.14 |
JPA 주요 매핑 어노테이션에 대해서! (0) | 2024.10.14 |
JPA 상속관계 매핑 MappedSuperclass (0) | 2024.10.11 |
JPA 상속관계 매핑 (0) | 2024.10.11 |