[SPRING] JPA - Transactional

RuiN·2022년 8월 1일
0
post-thumbnail

JPA Transactional

Entity LifeCycle ( 생명주기 ) 에서 잠시 다루었던 Transactional 을 더 다루어 볼까 합니다.


checked / unchecked Exception

  • Checked Exception
    • Exception의 상속받는 하위 클래스 중 Runtime Exception을 제외한 모든 Exception
  • Unchecked Exception
    • Runtime Exception 하위 Exception

간단하게 짚고 갑시다.
Checked Exception 의 경우에는 RollBack이 일어나지 않습니다.
그렇다면 Checked Exception 의 경우에도 롤백을 설정하고 싶다면!

@Transactional(rollbackFor = Exception.class)

위와 같이 롤백시키고 싶은 예외 Class를 지정해 주면 됩니다.
여러개로 설정이 가능하기도 합니다.


Junit Test

@Service
@RequiredArgsConstructor
public class BookService {

    private final BookRepository bookRepository;
    private final AuthorRepository authorRepository;

    @Transactional
    public void putBookAndAuthor()  {
        Book book = new Book();
        book.setName("JPA 시작하기");

        bookRepository.save(book);

        Author author = new Author();
        author.setName("martin");

        authorRepository.save(author);

        throw new RuntimeException("오류가 나서 DB commit 이 발생하지 않습니다.");

    }

}

위와 같은 BookService 라는 서비스를 하나 생성합니다.

@SpringBootTest
class BookServiceTest {

    @Autowired
    private BookService bookService;

    @Autowired
    private BookRepository bookRepository;

    @Autowired
    private AuthorRepository authorRepository;


    @DisplayName("1. transactionTest ")
    @Test
    void test_1(){
        try {
            bookService.putBookAndAuthor();
        } catch (RuntimeException e) {
            System.out.println(">>>> " + e.getMessage());

        }

        System.out.println("books : " + bookRepository.findAll());
        System.out.println("authors : " + authorRepository.findAll());

    }

}

그리고 JUINT테스트( transactionTest ) 를 생성합니다.

테스틀 실행해보면 당연히! 예외발생에 롤백이 생기겠죠?

books : []

authors : []

다음과 같이 빈 배열 (Null) 값이 출력이 됩니다.

그런데 만약 여기서

@Service
@RequiredArgsConstructor
public class BookService {

    private final BookRepository bookRepository;
    private final AuthorRepository authorRepository;


    public void put() {
        this.putBookAndAuthor();
    }

    @Transactional
    void putBookAndAuthor()  {
        Book book = new Book();
        book.setName("JPA 시작하기");

        bookRepository.save(book);

        Author author = new Author();
        author.setName("martin");

        authorRepository.save(author);

        throw new RuntimeException("오류가 나서 DB commit 이 발생하지 않습니다.");

    }

}

Transaction 할 putBookAndAuthor를 실행시켜주는
Put이라는 메소드를 만들어서 테스트를 실행시킨다면?

@SpringBootTest
class BookServiceTest {

    @Autowired
    private BookService bookService;

    @Autowired
    private BookRepository bookRepository;

    @Autowired
    private AuthorRepository authorRepository;


    @DisplayName("1. transactionTest ")
    @Test
    void test_1(){
        try {
            bookService.put();
        } catch (RuntimeException e) {
            System.out.println(">>>> " + e.getMessage());

        }

        System.out.println("books : " + bookRepository.findAll());
        System.out.println("authors : " + authorRepository.findAll());

    }

}

실행 결과는~?

books : [Book(super=BaseEntity(createdAt=2022-08-01T11:39:11.703, updatedAt=2022-08-01T11:39:11.703), id=1, name=JPA 시작하기, category=null, authorId=null)]

authors : [Author(super=BaseEntity(createdAt=2022-08-01T11:39:11.765, updatedAt=2022-08-01T11:39:11.765), id=1, name=martin, country=null)]

위와 같이 롤백이 일어나지 않게됩니다.

그냥 이렇다 하고 외워도 상관은 없습니다만..

스프링 컨테이너에서 실행시킬때 내부에 있는 transaction의 경우는 무시된다고 합니다.

profile
어디까지 올라갈지 궁금한 하루

0개의 댓글