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