JAN's History

스프링과 JPA를 이용한 웹개발_Spring Data JPA 2 본문

스프링

스프링과 JPA를 이용한 웹개발_Spring Data JPA 2

JANNNNNN 2024. 4. 6. 11:05

쿼리 결과 제한

first나 top 키워드를 사용하여 검색 결과 중 일부만 조회

페이징이나 슬라이싱을 함께 사용할 경우, 제한이 적용된 조회 결과에서 수행

  • 페이징이 먼저 되고, 그 값에서 슬라이싱이 사용되는 것처럼!

Entity Graph

패치전략

  • 기본적으로 EAGER나 LAZY 둘 중 하나를 사용
  • static하게 결정되므로 런타임 시 동적으로 전략 수정이 불가
  • 전략이 수정되면 어플리케이션 수정 및 컴파일
  • EntityGraph의 목적
    • 연관된 엔티티를 패치할 때 성능 향상
    • 객체 그래프 탐색의 형태로 데이터를 조회할 수 있음
    • 모든 연관관계를 Lazy로 설정하면 함께 조회시 추가적 JPQL을 작성해야 하지만 이를 EntityGraph를 사용하면 더 편리함

[Post의 연관관계 분석]

하나의 Post에는 여러개의 Comment를 포함할 수 있기 때문에 @OneToMany

한명의 User는 여러개의 Post를 포함할 수 있기 때문에 @ManyToOne

 

그.래.서 Post를 조회할 때 user와 comment를 동시에 조회할 수 있어야하고,

comment[0],[1]를 조회할 때에는 user 정보도 동시에 가져올 수 있어야 한다.

Entity Graph

  • 어노테이션으로 FetchType.LAZY 혹은 FetchType.EAGER를 지정했으므로 패치 타입이 고정
  • 런타임때 변경시킬 방법이 없음

🤨그러나 때로는 Post를 조회할 때 comment만 조회하고 싶을 수도 있는데, 이럴 때 이 Graph를 어떻게 조회해야하는가?

그럴 땐 NamedEntityGraph를 사용하자!

  • attributeNodes: 함께 조회될 엔티티 그래프를 나열
  • NamedAttributeNode: taget 엔티티가 조회될 때, 함께 조회될 연관 엔티티 이름!

⏩조회하고 싶은 엔티티만 뽑기는 성공! 그러나 아직 동시에 조회하기는 실패..

위와 같이 현재 순차적으로 실행중임 ㅠㅠ

그럴땐 subgraphs를 사용하자!

앞선 예제에서 더 나아가 Post에 속한 Comment를 작성한 User도 함께 조회(subgraphs 사용)

⏩ Post를 조회할 때, 글쓴이 댓글 댓글의 글쓴이 를 한 번에 조회할 수 있다!

하지만 NamedEntityGraph 정적이기 때문에 수정이 용이하지 않다..

그래서 등장한 entityManager.createEntityGraph!!

어노테이션을 이용하여 명시적으로 엔티티 그래프를 구성하는 것이 아닌 JPA API를 이용하여 동적으로 구성 가능하다!

Post에 subject와 user 추가하면 동시에 조회 가능!

  • comments와 연관된 user를 포함하는 subgraph생성
entityGraph.addSubgraph("comments").addAttributeNodes("user");
  • 조회
Map hints = new HashMap()
hints.get("javax.persistence.fetchgraph", entityGraph);
Order order = em.find(Post.class, postId, hints);

➡️언뜻보면 joinfetch와 Entity Graph이 비슷해보일 수 있지만, 차이점을 정리해보자면

joinfetch는 innerJoin을 사용하고 Entity Graph는 outerJoin을 사용하며 동적으로 사용할 수 있다!

Locking

Lock 모드 설정

  • 여러 트랜잭션에 의해 레코드가 수정될 경우, 동시성 문제로 인해 데이터 유실 혹은 일관성이 깨지는 문제가 발생
    • 동시성 문제 : 데이터베이스는 트랜잭션 단위로 작업을 수행하게 되는데, 그때 하나의 레코드에 데이터를 동시에 주고받을 때 유실 혹은 일관성이 생길 수 있다.
  • 이 동시성 문제는 내 트랜잭션이 끝나지 않았는데도 불구하고, 다른 트랜잭션이 관여하기 때문에 발생되는 것이다!
  • 그래서 Lock으로 관여하지 못하게 막는 것.

Lock에는 여러가지 모드가 있고, 쿼리메소드를 정의할 때 락의 모드를 정의할 수 있다.

위에서 @Lock(LockModeType.READ)처럼!

Lock 종류

낙관적 잠금

  • 트랜잭션간 동시성 문제는 거의 발생되지 않을껄? 이라는 낙관적인 style
  • 커밋 전(=비즈니스로직 종료시점), 각 트랜잭션은 다른 트랜잭션이 나의 트랜잭션에서 수정된 사항을 변경하지 않았는지 확인
  • 만약 수정에서 충돌이 발생한다면 Rollback 아니면 그냥 commit
  • 읽기, 쓰기에 제약을 두는 것이 아닌 충돌 감지 수준의 처리

비관적 잠금

  • 보나마나 동시성 문제가 발생할꺼야라는 부정적인 Sytle
  • write 전, 먼저 권한을 얻음
  • 만약 권한을 얻지 못하면 수정할 수 없음

낙관적 락은 커밋 전에 충돌을 감지한다. 만약, 충돌이 자주 발생하면?

➡️ 충돌 감지+ 예외처리 + Rollback → 차라리 엄격하게 접근 권한을 관리하자(비관적 락)

Exclusive lock (배타적 잠금)

  • 쓰기 잠금
  • 특정 트랜잭션에서 데이터를 변경하고자 할 때(write) 해당 테이블 or 레코드를 다른 트랙잭션에서 읽거나 쓰지 못하게 막음

Shared lock (공유 잠금)

  • 읽기 잠금
  • 특정 트랜잭션에서 데이터를 읽고자 할 때(read), 다른 트랜잭션도 함께 읽을 수 있도록 허용
  • 단, 변경은 허용하지 않음

낙관적락의 사용 방법 예시

  • JPA에서는 @Version이나 timestamp를 이용하여 낙관적 락을 구현
  • 특정 필드에 @Version이 붙은 필드를 추가(엔티티 클래스에 하나의 @Version 명시가능함!)

LockModeType

Repository를 개인적으로 만드는 방법

• 데이터 JPA가 제공해주는 것이 충분하지 않을 때

UserRepository를 상속받을 때 다중 상속을 받음!