N+1에 대해 학습하다보니 Hibernate의 Bag, List, Set이란 것을 접하게 되었다. 자바 ORM 표준 JPA 프로그래밍에 나온 내용을 정리해보았다.
아래는 모두 '자바 ORM 표준 JPA 프로그래밍'에 나와있는 내용이다.
java 컬렉션 | hibernate 내장 컬렉션 | 중복 허용 | 순서 보관 |
---|---|---|---|
Collection, List | PersistentBag | O | X |
Set | PersistentSet | X | X |
List + @OrderColumn | PersistentList | O | O |
엔티티 필드에 포함된 Java 컬렉션이 영속상태가 되면 Hibernate가 제공하는 컬렉션으로 타입이 변경된다.
하이버네이트는 컬렉션을 효율적으로 관리하기 위해 엔티티를 영속 상태로 만들 때 원본 컬렉션을 감싸고 있는 내장 컬렉션을 만들고 사용하게 한다. 따라서 다음처럼 즉시 초기화해 사용하는 것을 권장한다.
List<Member> members = new ArrayList<>();
'ArrayList'로 초기화하면 영속상태가 되었을때 'PersistentBag'으로 바뀐다.
Collection, List는 엔티티를 추가할 때 중복된 엔티티가 있는지 비교하지 않는다. 따라서 엔티티를 추가해도 지연 로딩된 컬렉션을 초기화하지 않는다.
'HashSet'으로 초기화하면 영속상태가 되었을때 'PersistentSet'으로 바뀐다.
'HashSet'은 중복을 허용하지 않아 add() 메서드로 객체를 추가할 때 마다 equals()를 통해 같은 객체가 있는지 비교한다.
Set은 엔티티를 추가할 때 중복검사를 한다. 따라서 엔티티를 추가할 때 지연 로딩된 컬렉션을 초기화한다.
'List' 인터페이스에 '@OrderColumn'을 추가하면 순서가 있는 특수한 컬렉션으로 인식한다.
데이터베이스에 순서 값을 저장해 조회할 때 사용하는데 Hibernate는 'PersistentList'를 사용한다.
순서가 있는 컬렉션은 데이터베이스에서 순서 값도 함께 관리한다. @OrderColumn의 name 속성에 'POSITION'이란 값을 주면 테이블에 'POSITION'이란 column이 생긴다.
테이블의 일대다 관계 특성상 'POSITION' column은 아래와 같이 '다'쪽에 생긴다.
ID | COMMENT | POSITION |
---|---|---|
1 | 댓글1 | 0 |
2 | 댓글2 | 1 |
3 | 댓글3 | 2 |
@OrderColumn은 단점이 많아 실무에서 사용하지 않는다고 한다. 개발자가 직접 'POSITION'을 관리하거나 @OrderBy를 사용하길 권장한다.