생성일: 2022년 3월 28일 오후 4:20
태그: JPA
Transactional에 들어가 보면
다양한 기능들이 제공된다.
—> 이번 시간에서는 isolation / propagation 를 알아보자!
동시에 발생하는 Transactional간에 데이터 접근을 어떻게 할건지 정리 역할을 한다.
총 다섯 가지를 제공!
`DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),`
`READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),`
`READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),`
`REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),`
`SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);`
특징
@Test
void isolationTest(){
Book book = new Book();
book.setName("jiiiin 강의");
bookRepository.save(book);
bookService.get(1L);
System.out.println(">>>> " + bookRepository.findAll());
}
=====================================================
// service
@Transactional
public void get(Long id){
System.out.println(">>> : " + bookRepository.findById(id));
System.out.println(">>> : " + bookRepository.findAll());
System.out.println(">>> : " + bookRepository.findById(id));
System.out.println(">>> : " + bookRepository.findAll());
}
위 와같이 설정을 해주고 debug 상태로 실행을 하면서 mysql console상에 직접 transaction에 들어가 update를 해보자
console상에는 none으로 값을 바꿔 주었지만 debug를 통해 값이 none으로 바뀌지 않고 있다. 이후 debug가 끝나면 끝내 none으로 바뀌어 졌다.
—> @Transactional(isolation = Isolation.
`READ_COMMITTED)`
설정을 바꾸고 실행을 해보자
한 단계 debug에서 다시
해주면
commit 된것처럼 알려준다.
이는 Dirty Read라고 불리며, 이는 문제성을 가지고 있다.
WHY? —> Rock이 발생
해당 메소드를 위와 같이 바꾸고 실행
쭉~~Debug를 실행하면
update 구간에서 Rock이 발생 이는 Transaction 이 mysql console상에 commit이 안 되었기 때문 commit을 하면 문제 없이 쭉 실행이 된다.
그렇다면 rollback이 되면 어떻게 되나?
rollback 이되어도 실행이 되었다..ㅠ JPA의 특징이 일부 반영이 된 Case
즉, console에서 update가 일어 났기 때문에 반영이 되었다.
해결법!
—> @Transactional(isolation = Isolation.*READ_COMMITTED*)
로 실행을 하면 commit된 데이터만 읽어온다.
근데 과연 **READ_COMMITTED**
는 문제가 없을까?
update 구문을 주석처리하고 실행을 해보자!
첫 번째 디버깅에서
1. start transaction;
2.update book set category='none';
를 해준 상태에서 디버깅을 하면 none 이 안 나온다.
다 실행을 한 뒤에 none이 뜬다.! JPA Inteface의 Entity cash 때문이다.
정확히는 위 사진처럼 Persist Context 내부에 있는 findById의 기존 캐시를 출력했기 때문에 update가 되지 않았던 것이다.
이는 clear를 통해 정리를 하면서 하면 된다.!
값을 두번 조회를 하는데 값이 같은 것을 조회하는 것은 이는 unrepeatable read 상태라 불린다. 이를 해결하는게 따로있다.
**@Transactional(isolation = Isolation.*REPEATABLE_READ*)--> 해결법**
위 코드를 추가를 하고 실행을하면 모든 transaction이 종료되고 값이 바뀐다. 이 또 한 문제가 있다.()
해당 nativeQuery를 추가하고,
update를 시켜주자!
그런다음 mysql로 가서
insert into book(id,name) values(2,'jpa 강의 2');
—> update가 아닌 insert를 넣어보고 실행을 해보자!
두 개의 쿼리에 대해서 처리가 된 케이스 이를 SERIALIZABLE
상태이다.
@Transactional(isolation = Isolation.*SERIALIZABLE*)
→추가하고 실행
첫 번째 Debug에서 실행을 해보자 Insert를 하자!
2번 상태에서 Wating 상태가 됐다. commit을 하게 되면
값이 나온다. 이는 wating 때문에 성능 저하를 야기하게 된다.
일반적으로 이는 쓰이지 않으며, repeatable_read / read_commit만 사용이 된다.