컬렉션 값 타입은 JPA(Java Persistence API)에서 값 타입(Value Type)을 컬렉션으로 사용하는 개념을 의미합니다. 즉, 값 타입이 여러 개 모여서 하나의 엔티티에서 관리될 때, 이를 컬렉션 값 타입이라고 합니다. 주로 Embeddable로 정의된 값 타입을 여러 개 관리할 수 있도록 컬렉션 형태로 사용합니다.
컬렉션 값 타입의 특징
- 값 타입(Value Type):
- 값 타입은 엔티티가 아닌, 데이터 그 자체를 의미하는 타입입니다. 기본 값 타입(예:
String
,Integer
)이나, 임베디드 타입(@Embeddable
로 정의된 클래스)이 있습니다. - 값 타입은 엔티티와는 다르게 식별자(ID)가 없으며, 동일한 값을 가지면 동일한 것으로 간주됩니다.
- 값 타입은 엔티티가 아닌, 데이터 그 자체를 의미하는 타입입니다. 기본 값 타입(예:
- 컬렉션으로 관리:
- 여러 값 타입 객체를 한 엔티티가 관리할 수 있습니다. 이를 컬렉션으로 관리할 때 주로
List
,Set
,Map
과 같은 컬렉션 자료구조를 사용합니다.
- 여러 값 타입 객체를 한 엔티티가 관리할 수 있습니다. 이를 컬렉션으로 관리할 때 주로
- 데이터베이스 테이블 매핑:
- 컬렉션 값 타입은 데이터베이스의 별도의 테이블에 저장됩니다. 주 엔티티와 1:N 관계처럼 보일 수 있으며, 컬렉션 값 타입을 저장하는 테이블은 외래 키로 주 엔티티의 식별자를 참조합니다.
- 생명주기 공유:
- 값 타입은 해당 엔티티의 생명주기에 종속됩니다. 즉, 엔티티가 삭제되면 그에 포함된 컬렉션 값 타입도 함께 삭제됩니다.
- 변경 불가:
- 값 타입 객체는 불변 객체로 설계하는 것이 좋습니다. 즉, 생성 후 수정하지 않고, 새로 생성하여 값을 변경합니다.
예시 코드
다음은 Address
라는 값 타입을 컬렉션 값 타입으로 사용하는 예시입니다.
1. 값 타입 클래스 (@Embeddable
로 정의)
import javax.persistence.Embeddable;
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
// 기본 생성자, 게터, 세터
public Address() {}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
// 불변 객체로 사용하기 위해 Setter 대신 생성자로 값 설정
public String getCity() {
return city;
}
public String getStreet() {
return street;
}
public String getZipcode() {
return zipcode;
}
// equals, hashCode 메서드 구현 (값 타입의 동일성 비교에 필요)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return city.equals(address.city) && street.equals(address.street) && zipcode.equals(address.zipcode);
}
@Override
public int hashCode() {
return Objects.hash(city, street, zipcode);
}
}
2. 컬렉션 값 타입을 사용하는 엔티티
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
// 컬렉션 값 타입 사용
@ElementCollection
@CollectionTable(name = "member_address", joinColumns = @JoinColumn(name = "member_id"))
private List<Address> addresses = new ArrayList<>();
// 기본 생성자, 게터, 세터
public Member() {}
public Member(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public List<Address> getAddresses() {
return addresses;
}
public void addAddress(Address address) {
addresses.add(address);
}
}
설명
@Embeddable
:Address
클래스는 값 타입을 나타내며@Embeddable
로 정의되었습니다. 값 타입은 기본적으로 엔티티가 아니므로, 별도의 테이블 없이 부모 엔티티의 테이블에 포함되거나, 컬렉션 값 타입처럼 별도의 테이블에 저장될 수 있습니다.
@ElementCollection
:@ElementCollection
은 엔티티가 아닌 값 타입 컬렉션을 관리할 때 사용합니다.List
,Set
등의 컬렉션을 값 타입으로 저장합니다.
@CollectionTable
:@CollectionTable
은 값 타입 컬렉션을 저장할 별도의 테이블을 지정하는데 사용됩니다. 여기서member_address
테이블이 생성되고,member_id
컬럼을 통해Member
엔티티와 연결됩니다.
- 컬렉션 값 타입 관리:
Member
엔티티는 여러Address
값을 가질 수 있습니다. 예를 들어, 한 사용자가 여러 주소를 가질 때List<Address>
컬렉션으로 관리할 수 있습니다.
컬렉션 값 타입의 제약사항
- 값 타입 수정 시 삭제 후 재삽입: JPA는 값 타입 컬렉션을 수정할 때, 기존 데이터를 삭제하고 새로 삽입하는 방식으로 처리합니다. 이는 데이터베이스 상에서 값 타입 컬렉션의 변경을 처리하는 일반적인 방식입니다.
- 영속성 전이 및 고아 객체 처리: 컬렉션 값 타입은 엔티티의 생명주기에 종속적이므로, 엔티티가 삭제되면 값 타입 컬렉션도 함께 삭제됩니다.
요약
- 컬렉션 값 타입은 JPA에서 값 타입을 컬렉션으로 관리하는 기능으로,
@ElementCollection
과@Embeddable
을 사용해 구현됩니다. - 컬렉션 값 타입은 데이터베이스에 별도의 테이블에 저장되며, 엔티티가 관리하는 값 타입의 모음을 표현합니다.
- 컬렉션 값 타입은 엔티티 생명주기에 종속적이고, 불변 객체로 사용하는 것이 권장됩니다.
CROSS JOIN
CROSS JOIN은 SQL에서 사용되는 조인 방식 중 하나로, 두 테이블의 모든 행을 조합하는 연산입니다. 카테시안 곱(Cartesian Product)이라고도 불리며, 두 테이블 간에 모든 가능한 행의 조합을 반환합니다. 즉, 첫 번째 테이블의 각 행과 두 번째 테이블의 모든 행을 매칭하여 결과를 반환합니다.
CROSS JOIN의 특징
- 카테시안 곱:
- 두 테이블의 모든 조합을 생성합니다. 예를 들어, 첫 번째 테이블에 5개의 행, 두 번째 테이블에 3개의 행이 있다면, 결과는 5 * 3 = 15개의 행이 됩니다.
- 결합 조건이 없음:
CROSS JOIN
은 두 테이블 간의 결합 조건을 사용하지 않습니다. 그래서 두 테이블의 모든 행을 단순히 조합합니다.
- 모든 행의 조합:
CROSS JOIN
은 두 테이블 간의 모든 가능한 행의 조합을 반환하므로, 필요 이상으로 많은 결과가 나올 수 있어 주의가 필요합니다.
CROSS JOIN의 예시
예시 테이블
- Customers 테이블:
customer_id | customer_name |
---|---|
1 | John |
2 | Jane |
- Products 테이블:
product_id | product_name |
---|---|
101 | Laptop |
102 | Phone |
103 | Tablet |
CROSS JOIN 쿼리
SELECT *
FROM Customers
CROSS JOIN Products;
결과:
customer_id | customer_name | product_id | product_name |
---|---|---|---|
1 | John | 101 | Laptop |
1 | John | 102 | Phone |
1 | John | 103 | Tablet |
2 | Jane | 101 | Laptop |
2 | Jane | 102 | Phone |
2 | Jane | 103 | Tablet |
이 결과는 Customers
테이블의 각 고객이 Products
테이블의 모든 제품과 조합된 결과를 보여줍니다. 두 테이블의 행들이 조합되어 총 6개의 행이 반환됩니다.
주의사항
- 대용량 테이블에서는
CROSS JOIN
을 사용할 때 주의해야 합니다. 테이블의 행이 많을 경우, 결과는 기하급수적으로 증가하여 성능에 큰 영향을 미칠 수 있습니다. - 의도적으로 사용:
CROSS JOIN
은 보통 특정 의도를 가지고 사용할 때만 적용하는 것이 좋습니다. 두 테이블의 모든 조합을 생성하고자 하는 특별한 경우가 아니라면, 조건이 없는CROSS JOIN
은 사용하지 않는 것이 좋습니다.
요약
- CROSS JOIN은 두 테이블의 모든 행을 조합하여 결과를 반환합니다.
- 테이블 간의 모든 가능한 조합을 반환하므로, 결과의 행 수가 매우 많아질 수 있습니다.
- 카테시안 곱을 수행하며, 결합 조건이 없기 때문에 두 테이블의 모든 행이 매칭됩니다.
'Study Memo' 카테고리의 다른 글
2024.09.23(월) { 페이징, @EntityGraph } (0) | 2024.09.23 |
---|---|
2024.09.20 (금) { WHERE 절, HAVING 절, GROUP BY, ORDER BY } (0) | 2024.09.23 |
2024.09.12(목) { 복합키 클래스( @IdClass, @EmbeddedId ) } (0) | 2024.09.12 |
2024.09.11(수) { 지연 로딩&즉시 로딩, n+1 문제, 다이나믹 업데이트, 알아야할 것들 } (0) | 2024.09.11 |
2024.09.10(화) { flush(), dirty, 스냅샷, 데이터베이스 정규화 } (0) | 2024.09.10 |