@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
public void putBookAndAuthor() {
Book book = new Book();
book.setName("JPA 시작하기");
bookRepository.save(book);
Author author = new Author();
author.setName("martin");
authorRepository.save(author);
}
}
@SpringBootTest
public class BookServiceTest {
@Autowired
private BookService bookService;
@Autowired
private BookRepository bookRepository;
@Autowired
private AuthorRepository authorRepository;
@Test
void transactionTest() {
bookService.putBookAndAuthor();
System.out.println("books : " + bookRepository.findAll());
System.out.println("authors : " + authorRepository.findAll());
}
}
@Transactional
public void putBookAndAuthor() {
...
...
...
throw new RuntimeException("오류나서 DB commit 발생안함");
@Test
void transactionTest() {
// 이런 코드는 지양하지만 학습을위한 Test기 때문에 이렇게 한다.
try{
bookService.putBookAndAuthor();
}catch (RuntimeException e){
System.out.println(">>>> " + e.getMessage());
}
System.out.println("books : " + bookRepository.findAll());
System.out.println("authors : " + authorRepository.findAll());
}
만약 그냥 checkException이라도 Rollback시키려면 아래 어노테이션을 적용하면된다.
@Transactional(rollbackFor = Exception.class)
public void put(){
this.putBookAndAuthor();
}
// @Transactional(rollbackFor = Exception.class)
@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 발생안함"); // unchecked Exception
}
Test 실행하고 JPA에서 Book을 Insert한 상태
Hibernate:
insert
into
book
(created_at, updated_at, author_id, category, name, publisher_id)
values
(?, ?, ?, ?, ?, ?)
-- mYsql에서 다른 트랜젝션을 실행 시켜서 독립성을 위반시켜보자.
start transaction ;
update book set category="none";
commit;
// Debug를 한번더 실행 시켜보면 JPA에서 실행한 트랜젝션에 영향을 끼치이 않을걸 볼 수 있다.
>>findAll>> [Book(super=BaseEntity(createdAt=2022-02-13T17:24:28.699, updatedAt=2022-02-13T17:24:28.699), id=1, name=JPA 강의, category=null, authorId=null)]
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void get(Long id){
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
Book book = bookRepository.findById(id).get();
book.setName("바뀔까?");
bookRepository.save(book);
}
start transaction ;
update book set category="none" where id=1;
rollback ;
// 이유는 JPA 쿼리때문이다.
Hibernate:
update
book
set
created_at=?,
updated_at=?,
author_id=?,
category=?, // 여기는 이미 category = "none" 으로 변경되어 있다.
name=?,
publisher_id=?
where
id=?
@DynamicUpdate
public class Book extends BaseEntity {
update
book
set
updated_at=?,
name=?
where
id=?
@Transactional(isolation = Isolation.READ_COMMITTED)
public void get(Long id){
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
Book book = bookRepository.findById(id).get();
book.setName("바뀔까?");
bookRepository.save(book);
}
start transaction ;
update book set category="none" where id=1;
commit ;
public interface BookRepository extends JpaRepository<Book, Long> {
@Modifying
@Query(value = "update book set category='none'", nativeQuery = true)
void update();
}
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void get(Long id) {
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
System.out.println(">>findById>> " + bookRepository.findById(id));
System.out.println(">>findAll>> " + bookRepository.findAll());
bookRepository.update();
}
TEST
디버그를 실행 시키고 DB transaction 실행해서 id 2를 만들어주자.
start transaction ;
insert into book ('id','name') values (2,'jpa 강의 2');
>>findAll>> [Book(super=BaseEntity(createdAt=2022-02-13T18:11:28.489, updatedAt=2022-02-13T18:11:28.489), id=1, name=JPA 강의, category=null, authorId=null)]
Hibernate:
update
book
set
category='none'
>>>> [Book(super=BaseEntity(createdAt=2022-02-13T18:20:07.023, updatedAt=2022-02-13T18:20:07.023), id=1, name=JPA 강의, category=none, authorId=null),
Book(super=BaseEntity(createdAt=null, updatedAt=null), id=2, name=jpa 강의 2, category=none, authorId=null)]