TIL - 0621

JPA - 영속성 컨텍스트

영속성 컨텍스트란

  • 순수 객체와 데이터베이스의 중간에 위치한 계층 : 중간 계층(레이어)을 둠으로써 얻는 이점이 있기때문에, JPA는 영속성 컨텍스트라는 레이어를 둠
  • 엔티티 매니져를 통해서 접근한다고 생각하면 됨
    • J2EE 환경 : 엔티티매니져 당 하나의 영속성 컨텍스트를 가지고 있음
    • 스프링 사용 환경 : 트랜잭션 내에서 여러 엔티티매니져가 하나의 영속성 컨텍스트에 접근(사용), 영속성 컨텍스트는 트랜잭션 끝나면 삭제

영속성 컨텍스트 특징

  • @Id로 엔티티 식별 : 식별자 값이 없으면 안됨(에러 발생)
/* 엔티티를 영속성 컨텍스트에 저장해두고 관리 */
Map<$ID_TYPE, $ENTITY_TYPE> entities = new HashMap<>();
  • 트랜잭션이 commit() 될 때 데이터베이스에 저장하며, 이전까지는 영속성 컨텍스트 내에서 저장, 관리 중
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();

transaction.begin();

em.persist(memberA);
em.persist(memberB);

transaction.commit();

영속성 컨텍스트 장점

  • 일단 알아야할 것 : 엔티티에 대한 작업을 하기위해서는 메모리로 가져와야함 - 조회를 해야함(영속성 컨텍스트에 관리 등록된 것 : 영속 상태)
  • 1차 캐시 : 트랜잭션 처리에서 엔티티를 조회하면 조회한 결과를 객체로 생성해서 클라이언트에게 반환해주면서 내부 map과 같은 자료구조에 저장해둠(@Id : 객체)
    • 캐시를 해두면 같은 엔티티에 대해서 매번 데이터베이스에 요청해서 가져오지 않아도 되기때문에 성능 향상
  • 동일성 보장 : 트랜잭션 처리에서 같은 엔티티 조회했을 때(@Id) 캐시해두었던 객체를 반환함 - 같은 객체임(동일함)
    • 동등과 동일 : 동등은 같은 값을 가지고 있는 것(equals)이지만 동일은 존재 자체가 같은 것(equals + hashCode)이라는 뜻
    • 트랜잭션 처리가 모두 성공하고 commit() 되기 전까지 같은 객체에 계속해서 수정을 가한다고 생각하면 됨
  • 트랜잭션 지원 지연 SQL 저장소 : 트랜잭션 처리에서 모든 처리가 끝났을 때 쿼리를 한꺼번에 날리기위해서 내부 저장소에 쿼리를 저장해두었다가 commit 때 날림
    • 개별 처리 끝날 때마다 날리고 모두 끝난 뒤 commit하는게 아니라 모두 끝났을 때 쿼리를 한꺼번에 날리고 commit()까지 : IO가 여러번이면 비효율적, 어차피 commit() 되지 않으면 쿼리들은 상관이 없어짐
  • 엔티티 변경 감지 : JPA는 최초 엔티티를 등록하면(조회, 생성/등록) 스냅샷을 떠놓았다가 스냅샷과 엔티티를 비교해서 변경된 부분을 찾음( flush() ) - 쿼리 작성
    • flush() : commit() 호출 전 flush() 호출로 최초 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾아 UPDATE 쿼리(쿼리 재사용을 위해 모든 컬럼을 UPDATE 쿼리 작성)를 작성함(변경된 컬럼만 쿼리 작성되도록 할 수도 있음 - @DynamicUpdate 사용, 업데이트 해야할 쿼리가 30개 이상일 때 효율적이라고 함)
    • flush() : UPDATE 뿐만 아니라 영속성 컨텍스트에 저장되어있는 SQL을 꺼내서 뿌리는 역할을 함 - commit() 전 호출
    • flush() 모드 : AUTO(커밋이나 쿼리를 실행할 때 플러시, 기본값), COMMIT(커밋할 때만 플러시)
    • 영속성 컨텍스트에 등록된(영속된) 엔티티만 가능함 : 조회나 코드에서 생성하고 관리를 등록한 엔티티
@DynamicUpdate
public interface UserRepository implements JpaReposiotry<User, Long> {

}
  • 지연로딩 : 연관관계에 있는 객체 정보를 당장 로딩하지않고(쿼리를 보내서 데이터를 받아옴), 필요할 때 정보를 로딩해옴

OOP

  • DI : 의존성 주입
    • 왜 의존성 주입을 하나? 역할 분리 + 런타임에 전략을 교체할 수 있도록(다이내믹)
    • 얻는 이점 : 역할분리로 인해 변경점을 최소화(한 부분) - 의존할 때 큰 개념에 의존만 해두면 구체적인 클래스가 변경되더라도 DI만 다른 것으로 해주면 됨

java-ims

  • 뷰를 사용하는 일반 컨트롤러 통합테스트를 할 때 예외가 발생해서 redirect 시켜주는 상황을 테스트한다면 HttpStatus.OK로 테스트해야함 : 최종적으로 클라이언트가 OK를 받음
  • 통합테스트에서만 할 수 있는 것이 있음 : 굳이 서비스 테스트에서는 로그인 여부를 묻지않아도 됨(컨트롤러 계층에서 걸러서 서비스 계층으로 넘어오기때문에)
  • 뷰 컨트롤러를 사용할 때 redirect를 하면 어디에 해당 패스가 기록될 것인가?
    • 헤더에 있음 : 컨트롤러에서 redirect: 를 했을 때
    • 바디는 리얼 데이터만 : html, json
  • Get일 때 redirect를 사용하면 최종 상태 코드로 OK
  • Post일 때 redirect를 사용하면 최종 상태 코드 FOUND