아직 JPA를 사용해본적이 없어 JPA공부해보고 내가 JPA를 사용하게 된다면 고려해봐야 할 것들을 정리해본다. 순서와 중요도는 전혀 상관이 없다.
엔티티를 @ToString 어노테이션으로 간단히 사용하려하면 연관관계끼리 toString을 하려고해서 무한루프에 빠질 수 있다. 때문에 연관관계 엔티티 끼리는 toString에서 제외 시켜주자
XXXToOne 관계는 기본 EAGER인데 LAZY로 변경해서 사용하는게 좋다. 둘다 N+1문제를 야기하지만 LAZY는 튜닝의 여지가 있고 필요에 따라 프록시를 사용해야 할 경우도 있기으니 LAZY를 기본으로 사용하자.
단뱡향 설계가 양방향 설계보다 무조건 좋다는 건 아니다. 하지만 우선 단방향 설계부터 하고 필요시에 양방향 설계를 추가하자.
다대다 관계는 RDB에서 사용되는 개념이지 객체지향과는 거리가 있기도 하고 성능상 좋지도 않다. 그러니 다대다 관계는 중간에 엔티티를 하나 더 사용해서 일대다, 다대일로 관계를 풀어서 사용하자.
값 타입은 변경이 불가능 해야한다. 값 타입을 클래스로 만들어서 참조해서 사용해서 헷갈릴 수도 있지만 클래스 자체가 값이라고 간주해야하며, 값은 항상 통채로 바꿔야지 클래스 속성 하나만 변경하고 그러면 안된다.
비단 JPA에서만 통용되는 말은 아니지만, 엔티티의 속성을 변경할 땐 세터로 하나씩 변경하는 것 보단 의미있는 메서드를 사용해서 변경하는 것이 유지보수 측면에서도 좋으니 이 방법을 추천한다.
JPA의 구현체로 Hibernate을 많이 사용할 텐데 하이버네트는 컬랙션을 한번 더 감싸서 사용하는데 이 때 초기화 되어 있지 않다면 제대로 동작을 안할 수 도 있다고 한다.
엔티티 업데이트는 변경감지와 marge()를 사용할 수 있는데 marge는 준영속 상태의 엔티티를 영속상태로 변경시키는 것으로 결국 변경감지를 사용하긴 한다. 하지만 변경감지는 필요한 속성만 변경할 수 있지만 marge는 엔티티를 통으로 업데이트 되기 때문에 엔티티를 잘 못 설정하면 Null값을 업데이트를 할 수 도 있다.
순수 JPQL은 결국 스트링 값이기에 런타임에서 오류를 발견하게 되고 동적 쿼리를 구성하기도 힘들다. 이 모든걸 해결해주는 것이 QueryDSL이며 컴파일 타임에 에러나 동적 쿼리에 아주 강력하다.
일단 api요청, 반환을 엔티티로 사용하게 될 경우 엔티티 자체가 노출 되는데 이건 지양해야하는 것 이다.
쿼리의 리턴타입을 엔티티를 받을지 DTO로 받을지는 서로 장단점이 있다. 엔티티로 받으면 일단 쿼리가 간단해지며 그래프 탐색도 하기 편하며 DTO로 받으면 쿼리문이 좀 지저분 해지고 그래프 탐색은 불가능하지만 fit한 결과를 얻을 수 있다.
JPA 일타강사이신 김영한님이 추천하는 방법은 다음과 같다.
XXXToMany관계를 가진다면 엔티티에서 컬렉션으로 참조하게 되는데 이게 참 골때려서 생각을 잘 해봐야한다.
우선 페치조인을 사용하면 모든 값을 읽고 메모리에서 페이징을 하려 하기 때문에 페이징이 안된다고 봐야함. 2개 이상의 컬랙션은 페치조인 안됨 등 문제가 많으니 다른 방식을 생각해볼 필요가 있다.
OSIV를 간단하게 설명하면 영속성 컨텍스트를 트랜잭션범위를 넘겨서도 사용할 수 있게 하는 방법이다. MVC패턴을 사용하면 VIEW단에서도 레이지로딩을 사용할 수 있다.
OSIV는 default값이 ture며 OSIV가 켜져있다면 리소스를 계속 사용하게 된다는 단점이 있다. 때문에 많은 처리량이 요구되는 api 서버는 OSIV를 끄고 처리량이 적은 관리자 페이지는 열어서 사용해도 얼추 괜찮고 영속성 컨텍스트를 유연하게 사용할 수 있어 편리함도 가져갈 수 있다.