JPA에 대한 개념적인 얘기를 좀 할거다.
JPA에서 가장 중요한 2가지가 ORM이랑 영속성 컨텍스트인데, 이 중 영속성 컨텍스트 개념을 배울거임.
전 시간에 실습한 내용을 보면 엔티티메니저 팩토리가 트랜잭션을 실행할 때마다 그 트랜잭션을 실행하는 엔티티 메니저를 만들어야 하고 이 메니저로 트랜잭션을 실행한다.
그래서 저장할 때 persist란 함수를 썼는데 사실 persist 할 때 바로 저장이 되는게 아니다. 실제로는 커밋을 수행해야 저장이 된다.
그럼 왜 persist할 때 저장하는것 처럼 얘기하고 persist를 하면 무슨 일이 일어나는 건가. 여기서 영속 개념이 나온다.
엔티티메니저니 뭐니 아무것도 없이 평소처럼 그냥 쌩 자바로 객체를 만들었을 때. 정말 아무 상태도 아니지만 영속 개념을 설명하기 위해 이 상태를 비영속 상태라고 정의했다. 그래서 그냥 new로 만들고 뭐 한게 없으니 비영속 상태다.
이제 persist를 하면 바로 db에 커밋되는게 아니라 영속 상태가 된다. 즉 영속 컨텍스트 안으로 들어온다.
자세히는 생명주기를 보면 감이 오는데, persist를 해서 영속성 컨텍스트에 들어간다. 즉 한번에 db랑 소통하는 걸 막는 중간 소통자 역할이 있다는 건데 이렇게 하면 좋은 점이 있으니 하는 것. 당장만 생각해도 무슨 일이 있을 때마다 바로바로 소통하면 그것도 낭비기 때문에 한번에 모아서 하여 자원을 효율적으로 사용할 수 있다.
영속 컨텍스트에 들어간다고 말했는데 자세히는 각 엔티티 메니저에서 트랜잭션 생성 시 거기서만 임시 캐시로써 딕셔너리 형태로 저장된다. 키는 객체 id로, value는 엔티티 객체를 저장한다. 엔티티메니저가 하나의 트랜잭션만 수행하려고 잠깐 만들고 사라지는 거라 이 1차 캐시도 잠깐 만들어지고 다시 사라져서 큰 의미는 없지만 정말 복잡해지 때는 의미 있을 수 있다. 그리고 잠깐이라서 성능 이점이 별로 없어도 이 캐시 덕분에 자바 객체적인 접근만으로도 가능해지게 만든다.
그래서 위 예제가 컨텍스트에 넣고 캐시로 불러오기 때문에 db 조회인 select를 안하는 모습이다.
어쨋든 딕셔너리 형태로 저장한다는 건 다른 애들도 저장하고 불러오기도 가능하단 뜻이다. 그래서 같은 객체를 여러 번 불러올 때 매번 db에서 불러오는게 아니라 트랜잭션 시작하고 처음 가져왔을 때 캐시에 저장했으므로 이 캐시를 통해서 불러와 성능 이점을 얻을 수 있다.
이건 자세히 생각해보면 객체를 캐시에 저장하고 그대로 불러오므로 둘은 같은 객체일 수밖에 없다. 물론 다른 컨텍스트에선 그쪽만의 1차 캐시가 따로 있어 거기서도 따로 만들고 캐시에 넣을거기 때문에 한 트랜잭션 안에서만 같다.
캐시를 사용하므로 버퍼처럼 한번에 모았다가 db에 보내주기도 가능하다. 심지어 이를 위한 batch_size 설정도 가능하다(직접 설정할 일은 별로 없음).
또 변경감지도 가능한데 중요한 점은 변경점을 저장하는 update같은게 없어도 변경한 뒤 그냥 커밋(사실 flush)하면 처음에 불러왔을 때 스냅샷이라는 곳을 만들어 저장해두었는데 이것과 비교해서 만약 값이 달라졌으면 변경 내용을 db에 반영하도록 쓰기 지연 sql 저장소에 명령어를 저장해놓고 커밋한다.
왜 update를 안하냐 할 수 있는데, 사실 그냥 자바 리스트를 다룰 때도 안의 요소 변경하려고 꺼내와서 다시 넣고 하는 작업은 안한다. 이런 점을 구현할 수 있게 한 것. 즉, 아까 말한 성능상 이점은 별로 없더라도 db 생각 안하고 최대한 자바 객체 적으로 생각하게 만들어 주는 수단으로써 가치가 더 큰 것이다.
삭제도 변경과 같음.
커밋 하기 전에 db에 빨리 반영하고 싶으면 flush 함수를 쓰면 된다(사실 직접 쓸 일이 거의 없음). flush를 쓴다고 1차 캐시에 있는 내용들이 비워지는게 아니라 쓰기 지연 sql 저장소에 쌓인 것들이 실제로 실행되어 db에 반영되는 것.
이 flush가 발생하는 경우는 직접 flush 함수를 실행해도 되지만, 트랜잭션 커밋하면 자동 호출되고 또 JPQL 쿼리를 실행해도 자동 호출 된다. 커밋은 알겠는데 JPQL은 select 해서 진짜 db에 있는거 가져올텐데 쓰기 지연 sql 저장소에만 있고 실제로 db에 없으니까 문제 될 수 있으니 호다닥 flush 하는 거.
이 플러스 모드를 setFlushMode해서 바꿀 수 있는데 진짜 바꿀일이 없다. 그냥 기본값(AUTO) 쓰자.
준영속은 별거 아니고 그냥 영속이었던 것, 즉 메니저 컨텍스트 1차 캐시에 있던 걸 빼내는거다. 빼내는 함수도 3개가 있다.
난 값을 변경하였지만 컨텍스트에서 없앴기 때문에 커밋을 하여도 변경점을 감지하지 못해 update가 안되는 모습.
처음과 두번째에 같은 걸 불러오므로 캐시를 사용해서 한 번만 불러와야 하지만 중간에 clear로 컨텍스트를 날렸기 때문에 다시 select로 불러와 캐시에 저장하는 모습. 변경이 된 것이 컨텍스트 안에 들어있기 때문에 커밋을 하였을 때 변경점이 감지되어 update되는 모습이다.
'CS > 김영한 스프링 강의' 카테고리의 다른 글
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 섹션 5. 연관관계 매핑 기초 (0) | 2023.09.18 |
---|---|
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 섹션 4. 엔티티 매핑 (0) | 2023.09.17 |
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 섹션 2. JPA 시작하기 (0) | 2023.09.14 |
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션7. 웹 계층 개발 (0) | 2023.09.14 |
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 섹션6. 주문 도메인 개발 (1) | 2023.09.11 |