일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- @Transactional Propagation
- intellij 핵심 단축키
- @TransactionalEventListener
- findTopBy
- intellij 즐겨찾기
- multipart테스트
- #docker compose
- 리눅스
- JPA
- git
- Linux
- 백명석님
- CompletableFuture
- ksql
- HandlerMethodArgumentResolver
- Stream
- java
- vue.js
- intellij favorites
- IntelliJ
- ksqldb
- 자바 ORM 표준 JPA 프로그래밍 정리
- 리팩토링 2판
- javascript case
- aws
- 원격 브랜 삭제
- Spring Cloud Netflix
- 친절한 SQL 튜닝
- 마이크로 서비스
- 자바 ORM 표준 JPA 프로그래밍
- Today
- Total
시그마 삽질==six 시그마
트랜잭션과 락 ,2차 캐시 본문
우아한 형제들의 김영한 팀장님의 '자바 ORM 표준 JPA 프로그래밍'을
구입하시길 강력 추천드립니다.
책 구입을 원하시는분은 요기를 클릭하시면 됩니다.
저자 직강 인프런 강의도 있습니다 궁금하신분은 요기를 클릭
하단의 내용은 제가 예전에 읽었던 내용을 요약 정리한 것입니다.
1. Transaction
데이터베이스에서 수행하는 논리적 작업 단위.
2. 특징
1)일관성(Consistency)
트랜잭션이 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지하는 것을 의미한다. 무결성 제약이 모든 계좌는 잔고가 있어야 한다면 이를 위반하는 트랜잭션은 중단된다.
2) 원자성(Atomicity)
all or nothing
3) 격리성(lsolation)
트랜잭션을 수행 시 다른 트랜잭션의 연산 작업이 끼어들지 못하도록 보장하는 것을 의미한다
4) 지속성(Durability)
트랜잭션을 성공적으로 마치면 결과가 영원히 반영 저장
중간에 시스템에 문제가 발생해도 데이터베이스 로그 등을 사용해 성공한 트랜잭션 내용을 복구해야 한다
3. 트랜잭션 격리 수준
격리수준(가능/문제) | DIRTY READ | NON-REPEATABLE READ | PHANTOM READ |
READ UNCOMMITED 레벨0 트랜잭션에서 처리중인 / 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용 |
O tx1 수정 tx2 읽음 tx1 롤백 tx2읽은 데이터 정합성문제 |
O |
O |
READ COMMINTED 레벨1(오라클 default) 트랜잭션이 커밋되어 확정된 데이터만 읽는 것을 허용 |
O tx1중 tx1 read ,tx2 수정&커밋 ,다시tx1 read (tx1내에서 두번 조회하는 사이에 tx2 수정 발생시) 반복해서 동일데이터 read x ex)회원b조회,수정,조회 |
O | |
REPEATABLE READ 레벨2(Mysql default) 선행 트랜잭션이 읽은 데이터는 선행 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제하는 것을 불허 |
O tx1중 tx1 read ,tx2 추가&커밋 ,다시tx1 read(tx1내에서 두번 조회하는 사이에 tx2 신규/삭제 발생시) 결과집합이 달라짐 |
||
SERIALIZABLE 레벨3 선행 트랜잭션이 읽은 데이터는 선행 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제하지 못할 뿐만 아니라 중간에 새로운 레코드를 삽입도 불허 |
- 트랜잭션 고립화 수준을 높이면 일관성( Consistency )은 향상되지만 더 넓은 범위의 Lock을 더 오랫동안 유지하는 방식을 사용하므로 동시성( Concurrency )은 저하된다.
4. 두번의 갱신 분실 문제
사용자 A와 B가 동시에 제목이 같은 공지사항을 수정한다고 가정
A가 수정 잠시후 B가 수정 A수정내용 사라짐(두번의 갱신 분실 문제)
재고차감 t1(-5개), t2(-1개) 100개 읽음. t1 이 -5해서 남은갯수 95개됨. t2 -1해서 남은 갯수 99개로 업데이트됨.
3가지 선택
1. 마지막 커밋 인정하기 -default
2. 최초 커밋만 인정하기<---@version 사용시 최초커밋만 인정하기 구현가능(A수정만 인정 B는 오류!,낙관적 락)
버전은 엔티티의 값을 변경하면 증가한다.
조회시점의 버전과 수정시점 버전 다르면 예외발생시킴
tx1조회, tx 2에서 엔티티 수정시 버전업. tx1 내용변경후 save시 예외발생!
update member set name=?, version=2 where id=? and version=1(이미 업데이트 된게 2라서 1이 안나옴)
3. 충돌하는 갱신 내용 병합하기
5. 낙관적 락과 비관적 락
낙관적 락 | 비관적 락 | |
정의 | tx 대부분은 충돌이 발생하지 않는다고 가정.애플리케이션이 제공하는 락사용 | tx 충돌이 발생한다 가정하고 이를 방지하기 위해 우선 락을 거는 방식 |
충돌 감지 | 커밋하는 시점에야 충돌여부 알 수 있음 | 데이터 수정 즉시 트랜잭션 충돌감지가능 |
성능 | good(tx불요) | bad |
롤백 | 비용과다 | 비용적음 |
충돌 | 충돌 적을시 유리 | 충돌 많을시 유리 |
1)낙관적 락
tx 대부분은 충돌이 발생하지 않는다고 가정.애플리케이션이 제공하는 락사용(JPA제공)
읽는 시점에 lock 사용 안하기에 데이터를 수정하는 시점에 다른 사용자에 의해 데이터가 변경되었는지 변경여부를 확인
트랜잭션을 커밋하기 전까지는 트랜잭션의 충돌 여부를 알 수 없음(커밋하는 시점에야 충돌여부 알 수 있음)
트랜잭션을 커밋하기 전까지는 트랜잭션 충돌을 확인하는 작업을 거치지 않기 때문에, 비관적락에 비해 성능이 더 좋음
롤백을 처리해주는 과정에서 update 쿼리가 추가적으로 더 발생
실제로 데이터 충돌이 자주 일어나지 않을것이라고 예상되는 시나리오에서 유리
@version 어노테이션 사용.
낙관적 락 없이 @version 만 사용하면 엔티티수정해야 버전을 체크하지만 낙관적 락과 같이 사용시는조회만 해도 버전을 체크함
2)비관적 락
tx 충돌이 발생한다 가정하고 이를 방지하기 위해 DB제공 락을 거는 방식. (기본적으로 읽는 시점에 lock)
데이터 수정 즉시 트랜잭션 충돌감지가능
데이터의 무결성이 중요하고, 충돌이 많이 발생하여 잦은 롤백으로 인한 효율성 문제가 발생하는것이 예상되는 시나리오에 유리.
(1)공유락(Shared Lock)(S) :Lock이 해제될 때까지 다른 트랜잭션은 읽을 수는 있지만 Write는 할 수 없음
동시에 데이터를 읽을 수는 있지만 Write는 할 수 없음
Trasaction 1에서 (S) Lock을 얻은 상태에서 Transaction 2에서 (S) Lock을 요청하는 경우 허용됨
Trasaction 1에서 (S) Lock을 얻은 상태에서 Transaction 2에서 (X) Lock을 요청하는 경우 거부됨
(2)배타적락(Exclusive Lock)(X): Lock이 해제될 때까지 다른 트랜잭션은 해당 데이터에 접근을 할 수 없음(읽기,쓰기 불가)
SELECT FOR UPDATE
. SELECT쿼리가 속한 전체 트랜잭션이 커밋될 때까지 쿼리 에서 반환된 행을 "잠글" 수 있습니다 . 해당 행에 액세스하려는 다른 트랜잭션은 시간 기반 대기열에 배치되어 대기하고 첫 번째 트랜잭션이 완료된 후 시간순으로 실행됩니다.
데이터를 수정하기위해 SELECT하는 중이기 때문에 다른 트랜잭션이 레코드를 SELECT하지 못하게 read, write락을 거는 구문
Trasaction 1에서 (S) Lock을 얻은 상태에서 Transaction 2에서 (S) Lock을 요청하는 경우 거부됨
Trasaction 1에서 (S) Lock을 얻은 상태에서 Transaction 2에서 (X) Lock을 요청하는 경우 거부됨
SELECT location FROM department where id=1 ; //결과 Sydney
session 1) start transaction;
session 1) SELECT location FROM department where id=1 FOR UPDATE;
session 2) SELECT location FROM department where id=1 FOR UPDATE; (무한로딩)
session 1) update sys.department set location="Sydney2" where id=1;
session 1) commit;
session 2) 무한로딩 해제되면서 결과 Sydney2 나옴
session 1) start transaction;
session 1) SELECT location FROM department where id=1 FOR UPDATE;
session 2) update sys.department set location="Sydney2" where id=1; (무한로딩)
session 1) update sys.department set location="Sydney3" where id=1;
session 1) commit;
session 2) 무한로딩 해제되면서 결과 Sydney2 나옴
https://unluckyjung.github.io/db/2022/03/07/Optimistic-vs-Pessimistic-Lock/
https://sabarada.tistory.com/m/175
6. JPA 락
READ_COMMITED+낙관적 버전관리 추천(두번의 갱신 분실 문제 예방)
락모드 | 타입 | 설명 |
낙관적락 | OPTIMISTIC | 낙관적락(조회만해도!! 버전 up) 즉한번조회한 엔티티는 tx1종료시까지 다른 tx에서 변경하지 않음을 보장 DIRTY READ ,NON-REPEATABLE READ방지 |
낙관적락 | OPTIMISTIC_FORCE_INCREMENT | 낙관적락+버전정보 강제화 수정한거 없어도 커밋시 버전업,논리적단위 버전관리 가능 게시물에서 파일만수정해도 버전업 |
비관적락 | PESMISTIC_READ | 리소스에 공유 락.다른 트랜잭션에서 읽기는 가능하지만 쓰기는 불가능 |
비관적락 | PESMISTIC_WRITE | 리소스에 배타 락을 걸게 됩니다. 다른 트랜잭션에서는 읽기와 쓰기 모두 불가능 |
비관적락 | PESMISTIC_FORCE_INCREMENT | 비관적락+버전정보 강제화 |
기타 | NONE | 락x |
7. 2차 캐시
애플리케이션에서 공유하는 캐시 ==공유캐시=2차캐시
네트워크 통해 DB 접근비용은 애플리케이션 메모리 접근 비용보다 비쌈! 고로 2차캐시사용
대부분의 JPA 구현체들은 애플리케이션 범위의 캐시를 지원하는데 공유캐시,2차 캐시라고함(애플리케이션 종료까지 유지!!)
영속성 컨텍스트(1차캐시)->2차캐시(1차가 캐시조회) ->2차캐시에 없으면 DB조회->2차캐시는 결과보관 및 원본이 아니라 복사본반환!!!
2차캐시는 DB기본키를 기준으로 캐시, pc다르면 객체동일성 보장안함
1)JPA 2차캐시
Entity위에 @Cacheable 어노테이션 추가
2)하이버네이트+ENCACHE로 2차캐시
@Cacheable:엔티티캐쉬만, @Cache:세밀한 캐쉬설정가능(하이버네이트 전용)
1.엔티티 캐시: 엔티티단위 캐시
2.컬렉션 캐시: 컬렉션이 엔티티 갖고 있으면 식별자만 캐시
3. 쿼리 캐시: 결과가 엔티티면 식별자 값만 캐시 (쿼리캐시 사용시 엔티티캐시도 같이 사용해야함! 안그럼 결과집합수만큼 조회함)
속성 | 설명 |
usage | CasheConcurrencyStrategy를 사용해서 캐시동시성 전략 설정 |
region | 캐시 지역설정 |
include | 연관 객체를 캐시에 포함할지 선택. all, non-lazy 옵션 선택가능 |
CasheConcurrencyStrategy 속성
속성 | 설명 |
NONE | 캐시 미설정 |
READ_ONLY | 읽기 전용설정.등록삭제는가능, 수정불가, 원본객체 반환 |
NONSTRICT_READ_WRITE | 동시에 같은 엔티티 수저시 데이터 일관성 깨짐 |
READ_WRITE | 읽기쓰기 가능. READ_COMMITTED 정도의 격리 수준을 보장. EHCACHE는 데이터 수정하면 캐시 데이터도 같이 수정 |
TRANSACTIONAL | 컨테이너 관리 환경에서 사용할 수 있다. REPEATABLE READ 정도의 격리 수준을 보장받을 수 있다. |
쿼리캐시 사용하기 위해서는
hints= @QueryHint(name="org.hibernate.cacheable", value="true") 를 넣어주며됨.
수정을 거의 안하는 테이블에 사용해야 효과적임.
org.hibernate.cache.spi.UpdateTimestampsCache 쿼리 캐시 영역은 만료되지 않도록 설정해야함 EHCACHE의 eternal="true" 옵션 사용시 캐시에서 삭제되지 않음
<cache name="org.hibernate.cache.spi.UpdateTimestampsCache" maxElementsInMemory="10000" eternal="true"/>
https://wildeveloperetrain.tistory.com/128
https://galid1.tistory.com/804
http://wiki.gurubee.net/pages/viewpage.action?pageId=21200923
'프로그래밍 > JPA' 카테고리의 다른 글
findTopBy, findTopBy (0) | 2020.10.22 |
---|---|
JPA 성능 최적화 (0) | 2020.08.08 |
JPA- 영속성 관리 (0) | 2020.04.10 |
스프링 데이터 JPA (0) | 2020.04.10 |
JPA -객체 지향 쿼리언어 (0) | 2020.04.09 |