[JPA] Transaction Manager

jpa, spring

JPA에서 Transaction 활용하기 #

Transaction 이란? #

데이터베이스에서 사용하며, 명령어의 논리적인 묶음.


Transaction 특성 #


@Transactional #

Book service와 테스트 클래스를 아래와 같이 생성.

@Service
public class BookService {
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private AuthorRepository authorRepository;

    @Transactional // ★
    public void putBookAndAuthor() {
        Book book = new Book();
        book.setName("Starting JPA Book");
        bookRepository.save(book);

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

        throw new RuntimeException("DB Error : No DB commit!!");
    }
}
@SpringBootTest
public class BookServiceTest {
    @Autowired
    private BookService bookService;
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private AuthorRepository authorRepository;

    @Test
    void transactionTest() {
        try {
            bookService.putBookAndAuthor();
        } catch (RuntimeException e) {
            System.out.println(">>> " + e.getMessage());
        }
        System.out.println(">>> books : " + bookRepository.findAll());
        System.out.println(">>> authors : " + authorRepository.findAll());
    }
}

@Transactional 하지않은 경우에는 에러에도 불구하고 결과값이 여전히 유효하게 나오지만.

books : [Book(super=BaseEntity(createdAt=2021-12-19T19:51:19.235446, updatedAt=2021-12-19T19:51:19.235446), id=1, Name=Starting JPA Book, category=null, authorId=null)]
authors : [Author(super=BaseEntity(createdAt=2021-12-19T19:51:19.392227, updatedAt=2021-12-19T19:51:19.392227), id=1, name=martin, country=null)]

@Transactional 처리를 하고나면 아래와 같이 결과값이 나오지 않는다.

> books : []  
> authors : []

이는 ACID의 트랜잭션의 All or Nothing 특성처럼, 일관성있게 처리됨을 알 수 있다.


put() 이라는 메소드를 만들어서, 트랜잭션이 걸린 putBookAndAuthor를 호출해보자.

@Service
public class BookService {
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private AuthorRepository authorRepository;

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

    @Transactional
    void putBookAndAuthor() {
        Book book = new Book();
        book.setName("Starting JPA Book");

        bookRepository.save(book);

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

        authorRepository.save(author);

        throw new RuntimeException("DB Error : No DB commit!!");
    }
}
@SpringBootTest
public class BookServiceTest {
    @Autowired
    private BookService bookService;
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private AuthorRepository authorRepository;

    @Test
    void transactionTest() throws Exception {
        try {
            // bookService.putBookAndAuthor();
            bookService.put();
        } catch (RuntimeException e) {
            System.out.println(">>> " + e.getMessage());
        }
        
        System.out.println(">>> books : " + bookRepository.findAll());
        System.out.println(">>> authors : " + authorRepository.findAll());
    }
}

put이라는 메소드에 진입하는 순간 이 bean 내부로 들어왔으며, 진입한 이후에 bean 내부에있는 다른 메소드를 호출하게되면 트랜잭션 어노테이션을 읽지 않아 동작하지 않음.


isolation() #

■ 트랜잭션 격리 4단계 #

단계가 아래로 내려갈수록 격리단계가 강력해지며, 데이터의 정확성을 보장해주지만, 동시에 동시처리하는 성능이 떨어지며, 위쪽으로 올라갈수록 성능은 올라가지만 일부 데이터를 정확성을 보장하지못하는 경우가 간혹 생김.


트랜잭션 전파 propagation() #

propagation: the act of producing a new plant from a parent plant.


Transaction Annotation Scope #

만약 class annotation, method annotation이 동시에 있다면, method annotation이 우선적으로 실행되며, class scope로 걸려있다면 각 method에 annotation이 걸려있는 효과와 같음.