2023-04-21-TIL
2023-04-21-TIL
Today I Learned
JPA 모범 사례
여러 글이 공통으로 강조하는 JPA 성능과 유지보수 원칙을 추리면 다음과 같다.
- 연관관계는 기본을 지연 로딩(
FetchType.LAZY)으로 두고, 함께 필요한 데이터는 쿼리마다 fetch join이나@EntityGraph로 가져온다.@ManyToOne과@OneToOne은 기본값이 즉시 로딩이라 명시적으로 바꿔야 한다. - 조회 전용 화면은 엔티티 대신 DTO 프로젝션으로 필요한 컬럼만 읽는다. 엔티티로 읽으면 영속성 컨텍스트에 올라가 스냅샷 비교 비용이 든다.
- SQL 로그를 켜 두고 N+1 쿼리를 개발 단계에서 확인한다.
- 대량 쓰기는 JDBC 배치 설정(
hibernate.jdbc.batch_size)과 함께 쓰고,IDENTITY전략은 INSERT를 바로 실행해야 해서 배치가 적용되지 않는다는 점을 알고 고른다.
Spring Data JPA 릴리스 노트와 버전별 레퍼런스 문서도 함께 보아 두면 기능이 어느 버전부터 생겼는지 확인할 수 있다.
- https://www.jrebel.com/blog/jpa-application-performance-best-practices
- https://thorben-janssen.com/hibernate-best-practices-for-readable-and-maintainable-code/
- https://www.oracle.com/technical-resources/articles/javaee/marx-jpa.html
- https://climbtheladder.com/10-spring-data-jpa-best-practices/
- https://cheese10yun.github.io/spring-jpa-best-15/
- https://www.jpa-buddy.com/blog/best-practices-and-common-pitfalls/
- https://www.baeldung.com/the-persistence-layer-with-spring-and-jpa
- https://www.adservio.fr/post/hibernate-performance-best-practices
- https://github.com/spring-projects/spring-data-jpa/releases
- https://docs.spring.io/spring-data/jpa/docs/3.1.0-RC1/reference/html/
- https://docs.spring.io/spring-data/jpa/docs/3.1.0-RC1/api/
- http://www.java2s.com/Tutorials/Java/JPA/4040__JPA_Query_AND_Condition.htm
Spring Data JPA에서 조건부 쿼리 만들기
검색 조건이 있을 때만 WHERE 절에 넣고 싶을 때, 메서드 이름 쿼리로는 조건 조합마다 메서드를 만들어야 해서 금방 한계에 부딪힌다. Spring Data JPA가 제공하는 대안은 두 가지다.
- Specification: 문서 설명대로 Criteria API로 표현한 엔티티에 대한 조건(predicate)이다. 리포지토리가
JpaSpecificationExecutor를 상속하면 조건 객체를and,or로 조합해 넘길 수 있다. 값이 없으면null을 반환하는 Specification을 만들어 조건을 빼는 방식이 흔하다. - Query by Example: 엔티티 예시 객체의 채워진 필드로 조건을 만든다. 간단하지만 문서는
firstname = ?0 or (...)같은 중첩 조건과 컬렉션 매칭을 지원하지 않는다고 적고 있다.
조건이 복잡해지면 Criteria API의 장황함 때문에 다음 절의 QueryDSL을 쓰는 경우가 많다.
- https://stackoverflow.com/questions/70165854/spring-data-jpa-how-to-form-a-conditional-query
- https://medium.com/codex/how-to-easily-do-conditional-querying-with-spring-data-jpa-123079aa09a6
- Specifications (Spring Data JPA)
- Query by Example (Spring Data JPA)
QueryDSL로 동적 쿼리 작성
QueryDSL은 엔티티에서 생성한 Q 클래스로 JPQL을 타입 안전하게 조립한다. 동적 조건은 BooleanBuilder에 조건을 쌓거나, 조건마다 BooleanExpression을 반환하는 메서드를 만들고 값이 없으면 null을 반환하게 하는 방식이 있다. where()에 넘긴 null 조건은 무시되므로 후자가 읽기 쉽고 조건 메서드를 재사용하기 좋다. 링크한 우아한형제들 발표 정리 글도 이 방식을 권한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public List<Member> search(String name, Integer minAge) {
return queryFactory.selectFrom(member)
.where(nameEq(name), ageGoe(minAge))
.fetch();
}
private BooleanExpression nameEq(String name) {
return name == null ? null : member.name.eq(name);
}
private BooleanExpression ageGoe(Integer minAge) {
return minAge == null ? null : member.age.goe(minAge);
}
- https://tecoble.techcourse.co.kr/post/2021-08-08-basic-querydsl/
- https://jojoldu.tistory.com/394
- http://querydsl.com/static/querydsl/latest/reference/html/
- https://velog.io/@youngerjesus/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%98%95%EC%A0%9C%EB%93%A4%EC%9D%98-Querydsl-%ED%99%9C%EC%9A%A9%EB%B2%95
- https://www.baeldung.com/rest-api-search-language-spring-data-querydsl
- https://velog.io/@jkijki12/Spring-QueryDSL-%EC%99%84%EB%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
- https://zetcode.com/springboot/querydsl/
- https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
- https://www.youtube.com/watch?v=MHxoUbyfblo
자연 키와 인조 키
자연 키(natural key)는 주민등록번호, 이메일, 사업자번호처럼 업무적으로 의미가 있는 값을 기본 키로 쓰는 것이고, 인조 키(artificial 또는 surrogate key)는 자동 증가 숫자나 UUID처럼 의미 없는 값을 새로 만들어 쓰는 것이다. 자연 키는 별도 컬럼이 필요 없지만, 업무 규칙이 바뀌면 값이 바뀌거나 유일하지 않게 될 수 있고, 그러면 그 키를 참조하는 모든 외래 키를 고쳐야 한다. 그래서 보통 기본 키는 인조 키로 두고 자연 키에는 유니크 제약을 거는 방식을 많이 쓴다. 인조 키 중에서도 자동 증가 값은 작고 정렬되어 인덱스에 유리하고, UUID는 여러 노드에서 충돌 없이 미리 만들 수 있지만 크고 무작위라 InnoDB처럼 기본 키 순서로 데이터를 저장하는 엔진에서는 삽입 위치가 흩어진다는 비교가 링크한 글들에 나온다.
- https://velog.io/@pyro/artificial-key-vs-natural-key#:~:text=%EC%9D%B8%EC%A1%B0%ED%82%A4%EC%99%80%20%EC%9E%90%EC%97%B0%ED%82%A4,%EA%B0%80%20%EB%90%98%EC%A7%80%20%EC%95%8A%EC%9D%84%20%ED%84%B0%EC%9D%B4%EB%8B%A4.
- https://warmth424.tistory.com/14
- https://multifrontgarden.tistory.com/180
- https://okky.kr/articles/400144
- https://velog.io/@tmdgusya/%EC%9D%B8%EA%B3%B5%ED%82%A4-UUID-VS-GEN-KEY
헥사고날 아키텍처와 클린 아키텍처
헥사고날 아키텍처(Ports and Adapters)는 핵심 비즈니스 로직이 외부와 소통하는 방식을 포트(인터페이스)로 정의하고, DB나 웹 같은 구체 기술은 어댑터로 구현해 꽂는 구조다. 클린 아키텍처는 Robert C. Martin이 헥사고날 등을 참고해 정리한 것으로, 엔티티, 유스케이스, 인터페이스 어댑터, 프레임워크와 드라이버의 동심원 계층을 두고 소스 코드 의존성은 안쪽으로만 향해야 한다는 의존성 규칙을 핵심으로 삼는다. 링크한 글의 정리대로 둘은 경쟁 관계라기보다 같은 목표(도메인을 프레임워크와 인프라에서 분리)를 다른 수준으로 설명한다. 헥사고날은 안과 밖의 경계를, 클린 아키텍처는 안쪽의 계층 구분까지 제시한다.
- https://www.gregorypacheco.com.br/posts/differences-between-clean-architecture-and-hexagonal-architecture-cshrp-dot-net.html
- https://dev.to/dyarleniber/hexagonal-architecture-and-clean-architecture-with-examples-48oi
액터 모델
엑터 모델은 Erlang을 만든 사람이 만들었다고 하는데, 한동안 많이 언급되다가 최근에는 좀 식은 느낌이라고 한다.
출처를 확인해 보면 액터 모델은 Erlang보다 앞선다. Wikipedia에 따르면 액터 모델은 1973년 Hewitt, Bishop, Steiger의 논문에서 시작됐고, Erlang은 이 모델의 대표적인 구현 사례로 자주 언급된다. 액터는 메시지를 받으면 다른 액터에게 유한한 수의 메시지를 보내거나, 새 액터를 만들거나, 다음 메시지를 처리할 동작(상태)을 정할 수 있는 계산 단위다. 상태를 공유하지 않고 메시지로만 소통하므로 락 없이 동시성을 다룰 수 있다.
언리얼 엔진 문서의 Actor는 게임 월드에 배치되는 객체를 가리키는 이름으로, 동시성 모델인 액터와는 다른 개념이다.
- https://en.wikipedia.org/wiki/Actor_model
- https://www.brianstorti.com/the-actor-model/
- https://zemuldo.com/blog/erlang-elixir-concurrency-model-5f26fddb356aef5185fd38b9
- https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Actors/ActorLifecycle/
Akka
Akka는 JVM에서 액터 모델을 구현한 툴킷이다. Akka 문서는 액터를 쓰는 이유를 이렇게 설명한다. 메서드를 호출하는 대신 메시지를 보내므로 보내는 쪽이 블로킹되지 않고, 액터는 받은 메시지를 한 번에 하나씩 순차 처리하므로 내부 상태를 락 없이 캡슐화할 수 있다. 메시지에는 반환값이 없어서 결과도 응답 메시지로 돌려받는다. 이 비동기 메시지 전달 위에 클러스터링, 영속 액터 같은 분산 기능이 올라간다.
- https://thinkpalm.com/blogs/introduction-akka-framework/
- https://doc.akka.io/docs/akka/current/typed/guide/actors-intro.html
- https://www.infoq.com/articles/Reactive-Systems-Akka-Actors-DomainDrivenDesign/
리액티브 아키텍처와 액터 모델
리액티브 시스템은 응답성, 탄력성, 회복성을 비동기 메시지 전달 위에 세우자는 설계 방향이다. 액터 모델은 메시지 기반이고 액터끼리 격리되어 있어 한 액터의 실패가 감독자(supervisor)에서 처리되므로, 리액티브 아키텍처를 구현하는 수단으로 자주 짝지어 설명된다. InfoQ 글은 여기에 DDD까지 엮어 Akka 액터로 리액티브 시스템을 설계하는 방법을 다룬다.
- https://medium.com/@manish.c.ghildiyal/reactive-architecture-and-actor-model-a38214a404a4
댓글
아직 댓글이 없습니다