BackEnd/패캠

[JPA] 트랜잭션

제이드Jade 2022. 2. 3. 15:28

*트랜잭션의 특징 : acid

원자성 : 전체 성공 or 전체 실패

일관성 : 데이터간의 정확성

독립셩 : 다른 트랜잭션이 중간 연산결과에 접근불가

영속성 : 상태가 영구적으로 db에 저장

 

* ddl-autocreate-drop하면 테스트 실행동안 테이블이 생기다가 끝나면 삭제됨

(>>디버그 브레이크 포인트를 통해 테이블 확인할 수 있음)

 

* 테이블에 데이터 추가하는 메서드를 @Transactional로 묶으면 메서드 중간에는 데이터가 추가되지 않고 메서드가 끝나고 한번에 처리됨

  @Transactional하면 java에서 제공하는 것과 스프링에서 제공하는 것 두가지가 있다. (여기선 스프링걸 써봄)

* 메서드가 끝나기 직전에 Exception을 발생하면 어떻게 될까?

           1) RuntimeException : rollback되어 연산들이 모두 취소, db에 반영되지 않는다.

           2) (Checked) Exception : 그래도 커밋이 된다. (대신 에러 처리 catch문이 필수이다)

           (*참고: new Exception(“msg”) : msg가 메시지가 되어 e.getMessage()하면 msg가 출력

                       @Transactional의 속성으로 rollbackFor이라는 것이 있는데 이 속성의 값으로 Exception.class를 취해주면 2)Checked Exception이라 해도 rollback이 되어 커밋되지 않는다.

* A라는 메서드에서 @Transactional인 메서드를 호출하는데, A라는 메서드를 호출하는 방식으로 메서드를 실행하면 어떻게 될까?

           => @Transactional은 무시됨.

           @Transactional 메서드가 public이 아닐경우 이런 실수를 많이 하므로 조심하길 바람

           참고) 호출되려는 메서드에서 에러가 던져지고 이걸 try-catch로 처리하지 않았다면(throw방식 포함) 이 메서드를 호출할 수 없다.

 

*isolation

0) DEFAULT : 사용하는 db설정에 따름

1) READ_UNCOMMITTED : 커밋되지 않아도 읽어온다.

2) READ_COMMITTED : 커밋된 것만 읽어온다.

3) REPEATABLE_READ : 커밋 여부와 상관없이 각 트랜잭션의 흐름은 방해받지 않는다.

4) SERIALIZABLE : 커밋이 되지 않은 트랜잭션이 있으면 다른 트랜잭션이 기다림

           => 밑으로 갈수록 강한 격리성, 데이터의 정합성 보낭 .but 수행성능 떨어짐

 

1) READ_UNCOMMITTED

 ㄴ 커밋되지 않은 걸 읽어오는 것을 더티리드라고 한다

 ㄴ 만약에 조작하고  -> 다른거 update 후 저장 -> 조작 rollback 해도, update된 결과에는 조작이 rollback되지 않는다. => jpa에서 update방식의 default가 변경필드 포함 모든 필드를 업데이트 하기 때문

                        ㄴ 조작을 rollback해도 이미 저장된건 rollback이 안됨.

                        update 된 것만 변경하려면 @DynamicUpdate를 엔티티에 달아주면 된다.

 

 2) READ_COMMITTED

 ㄴ 한 트랜잭션 중간에 다른 트랜잭션이 변경하고 커밋해도 그 후에 findId를 하면 변경된 값을 가져오진 않는다. 1차캐쉬 때문이다. => manager.clear로 해결할 수 있다.

ㄴ 하지만 다른 트랜잭션에서 변경하고 커밋을 하면 한 트랜잭션 내의 흐름이 깨지는건 마찬가지이다. => unrepeatable read

 

3) REPEATABLE_READ (mysql)

ㄴ 초기의 db상태를 스냅샷으로 찍어둬서 한 트랜잭션에서는 이것만 계속 사용

ㄴ 하지만 phantom read : 아직 안들어온 데이터도 미리 변경을 함.

           (ex. ‘b 트랜잭션에서 레코드 insert -> a 트랜잭션에서 한 필드 전체 값을 update 후 커밋 -> b 트랜잭션도 커밋했을 시 분명 b트랜잭션 커밋 전에 update해서 insert된 레코드에는 update가 반영되지 않아야 하는데, insert된 레코드의 필드값 까지 update)

 

 

propagation

1) REQUIRED (default) : 기존에 트랜잭션이 있다면 그것을 쓰고, 없으면 새로 생성 (ex. save 메서드)

                                  => 즉 두 트랜잭션은 서로 연결되어 있어서 둘다 성공 or 실패한다.

2) REQUIRES_NEW : 항상 별도의 transaction 생성 => 두 트랜잭션은 독립적, 성공/실패도 따로

3) NESTED : 무조건 호출하는 쪽의 트랜잭션만 사용. -웬만해선 사용하지 않는다.

=> 호출되는 트랜잭션에 오류나도 호출하는 쪽은 ㄱㅊ

4) SUPPORTS : 호출하는 쪽의 트랜잭션이 있다면 그것을 쓰고, 없어도 생성하지 않고 처리.

5) NOT_SUPPORTED : 트랜잭션들은 독립적, 근데 호출되는 쪽은 트랜잭션을 생성하지 않음

6) MANDATORY : 이미 생성된 트랜잭션이 필수로 있어야 한다. 없으면 생성하지 않고 오류 발생

7) NEVER : 이미 생성된 트랜잭션이 무조건 없어야 한다. 있으면 오류발생

 

* 참고) 트랜잭션의 단위는 클래스나 메서드이다.(@TransactionalTarget 속성)

           ㄴ 클래스 단위면 해당 메서드들이 모두 트랜잭션 단위가 된다.