트랜잭션
트랜잭션(Transaction)의 정의를 내려보자면, 트랜잭션은 Database의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업 단위나 한 번에 수행되어야 할 일련의 연산을 의미한다.
만약 데이터베이스의 데이터를 수정하는 도중에 예외가 발생된다면 어떻게 해야 할까?
DB의 데이터들은 수정이 되기 전의 상태로 되돌아가져야 하고, 다시 수정 작업이 진행되어야 할 것이다.
이렇듯 여러 작업을 진행하다가 문제가 생겼을 경우 이전 상태로 롤백하기 위해 사용되는 것을 트랜잭션(Transction)이라고 한다.
트랜잭션은 더 이상 쪼갤 수 없는 최소 작업 단위를 의미한다. 그래서 트랜잭션은 commit으로 성공하거나 rollback으로 실패 이후 취소되어야 한다. 하지만 모든 트랜잭션이 동일한 것은 아니고 속성에 따라 동작 방식을 다르게 해 줄 수 있다.
예를 들어 1개의 새로운 데이터를 추가하는 와중에 에러가 발생하면 해당 추가 작업은 없었던 것처럼 되돌려진다. 하지만 만약 여러 개의 작업에 대해 롤백을 하려면 어떻게 해야 될까? 여러 개의 작업을 1개의 트랜잭션으로 관리해야 할 것이다.
위에서 설명한 것과 마찬가지로 트랜잭션의 마무리 작업으로는 크게 2가지가 있다.
- 트랜잭션 커밋: 작업이 마무리된다.
- 트랜잭션 롤백: 작업을 취소하고 이전의 상태로 돌린다.
만약 여러 작업이 모두 마무리되었다면 트랜잭션 커밋을 통해 작업이 마무리되었음을 알려주어 반영해야 하며, 만약 문제가 생겼다면 작업 취소를 위해 트랜잭션 롤백 처리를 해주어야 한다.
게시판을 예로 들어보자.
게시판 사용자는 게시글을 작성하고, 올리기 버튼을 누른다. 그 후에 다시 게시판에 돌아왔을 때, 게시판은 자신의 글이 포함된 업데이트된 게시판을 보게 된다.
이러한 상황을 데이터베이스 작업으로 옮기면, 사용자가 올리기 버튼을 눌렀을 시, Insert 문을 사용하여
사용자가 입력한 게시글의 데이터를 옮긴다. 그 후에, 게시판을 구성할 데이터를 다시 Select 하여 최신 정보로
유지한다. 여기서 작업의 단위는 insert문과 select문 둘 다 를 합친 것이다.
이러한 작업 단위를 하나의 트랜잭션이라 한다.
관리자나 개발자가 하나의 트랜잭션 설계를 잘하는 것이 데이터를 다루는 것에 많은 이점이 있다.
참고로 스프링의 모든 Repository는 기본적으로 트랜잭션이 적용되어 있다.
(repository 구현체인 SimpleJpaRepository에 @Transactional이 적용되어 있기 때문이다)
@Transactional
repository나 service계층(repository를 사용하는 계층)에서 사용된다.
기본적으로 RuntimeException이나 error가 발생하면 해당 트랜잭션을 롤백시킨다.
Checked Exception에는 롤백이 일어나지 않는다.
※ 옵션
readOnly | 데이터를 변경하는 operation이 없는 경우 true로 설정해주는 것이 좋다. |
Isolation | 여러개의 트랜잭션이 동시에 데이터베이스에 접근했을때, 해당 트랜잭션들을 어떻게 처리할 것인지에 대한 설정(동시에 처리할 것인지, 하나 하나 처리할 것인지 등) 기본값은 default로 DB의 기본값을 따라간다.(대부분 READ_COMMITTED 방식이 default값이다.) |
Propagation | 트랜잭션을 어떻게 전파시킬 것인지에 관한 것이다. 예를 들어 @Transactional을 가지고 있는 메서드가 있고, 그 메서드 안에서 다른 메서드를 호출했는데 그 메서드도 @Transactional을 가지고있는 경우, 첫 번째 메서드가 가지고 있던 트랜잭션을 두 번째 메서드가 이어갈 것이냐, 두 번째 메서드 자체에서 트랜잭션을 만들어서 따로 사용할 것이냐를 결정하는 것이다.(nested transaction에 관한 내용) |
TIP
JPA 구현체로 Hibernate를 사용할 때, 트랜잭션을 readOnly로 사용하면 좋은 점이 있다.
flush모드를 NEVER로 설정해 줘서, 해당 트랜잭션 안에서는 Dirty checking을 하지 않게 해 준다.
- flush모드: 데이터베이스와 sync를 맞춰주는 모드. 즉 언제 데이터베이스에 sync를 할 것인지에 관한 것이다. 기본값은 보통 커밋하거나 데이터를 가져오기 전에 flush 하게 되어있다.
- Dirty checking: 트랜잭션 내에서 변경이 일어날 시, PersistanceContext가 변경을 감지하여 데이터베이스에 반영하는 것
데이터를 읽어올 것이 많은 경우, DirtyChecking을 꺼놓으면 성능이 많이 올라간다.
Ex. findById 같은 경우 데이터를 읽어오기만 하기 때문에, readOnly 해주는 것이 좋다.(데이터 변경이 일어나지 않을 것이므로)
@Transactional(readOnly=true)
<T> List <T> findByPost_Id(Long id, Class<T> type);
'Java' 카테고리의 다른 글
[QueryDSL] DATE_FORMAT 사용하기 (0) | 2022.08.30 |
---|---|
[React] 비동기로 동작하는 setState에 대한 (0) | 2022.08.30 |
[MYSQL] AES_ENCRYPT / AES_DECRYPT (0) | 2022.08.18 |
[Java] JAR vs War 비교 분석 (0) | 2022.08.10 |
[React] JWT 토큰과 localStorage 로그인 (0) | 2022.08.08 |