# Spring @Transactional ์ฌ์ฉ
์๋ณธ ๋ธ๋ก๊ทธ ๊ธ (opens new window)
# Transactional
Spring ์์ JPA ๊ธฐ์ ์ ์ธ ๋ ๋นผ๋์ ์ ์๋ ๊ธฐ๋ฅ์ค ํ๋๋ @Transactional ์ด๋ค.
์๋์ ๊ฐ์ด ๋ง์ ํธ๋ฆฌ์ฑ์ ์ฐ๋ฆฌ์๊ฒ ์ ๊ณตํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
- transaction begin, commit์ ์๋ ์ํํด์ค๋ค.
- ์์ธ๋ฅผ ๋ฐ์์ํค๋ฉด, rollback ์ฒ๋ฆฌ๋ฅผ ์๋ ์ํํด์ค๋ค.
๊ทธ๋ ๊ธฐ์, ๋ง์ ๋ณด์ผ๋ฌ์ฝ๋๋ฅผ ์ค ์ผ ์ ์๊ธฐ ๋๋ฌธ์, ์๋์ ๊ฐ์ด ํธ๋ฆฌํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
Note. ๋ฌธ์ ์ํฉ์ ์ต์ง๋ก ๋ง๋ค๊ธฐ ์ํด ์ฝ๋ ํจ์จ์ฑ์ด ์ข์ง ์์ ์ ์์ต๋๋ค.
public class BooksImpl implements Books {
@Transactional
public void addBook(String bookName) {
Book book = new Book(bookName);
bookRepository.save(book);
book.setFlag(true);
}
}
๋ฌธ์ ๋ ์์์์ ์ด addBook ๋ฉ์๋๋ฅผ Books ํด๋์ค ๋ด๋ถ์์ ์ฌ์ฉํ ๋ ๋ฐ์ ํ ์ ์๋ค.
public class BooksImpl implements Books {
public void addBooks(List<String> bookNames) {
bookNames.forEach(bookName -> this.addBook(bookName));
}
@Transactional
public void addBook(String bookName) {
Book book = new Book(bookName);
bookRepository.save(book);
book.setFlag(true);
}
}
ํน์, addBooks ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋, ์ด๋ค๊ฒ์ด ๋ฌธ์ ๊ฐ ๋ ์ ์๋์ง ์์์ด ๊ฐ์๋์?
๋ฌธ์ ๋ addBooks ๋ฉ์๋ ๋ด๋ถ์์ ํธ์ถํ๋ addBook ๋ฉ์๋์ @Transactional ์ด๋ ธํ ์ด์ ์ด ์ ์ฉ๋์ง ์๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ ๊ธฐ์, ํด๋น ์ฝ๋๋ฅผ ์คํํ๋๋ผ๋ Database์๋ ์ ์ฅ๋ Book ์ ๋ณด์ Flag ์ปฌ๋ผ์ ์ ์์ ์ผ๋ก ์ ๋ฐ์ดํธ ๋์ง ์์ต๋๋ค.
bookRepository ์ save ๋ฉ์๋๋ ์์ฒด์ ์ผ๋ก @Transactional ์ด๋ ธํ ์ด์ ์ด ๋ถ์ด์์ด, ์ ์์ ์ผ๋ก ์ฝ๋๊ฐ ์ํ์ด ๋์ด Database์ insert ๋ฅผ ์ํํฉ๋๋ค.
ํ์ง๋ง, update ์ ์ญํ ์ ํ๋ book ๊ฐ์ฒด์ ๋ณ๊ฒฝ๊ฐ์ง๊ฐ ๋์ํ์ง ์์, Flag ์ปฌ๋ผ์ ์ ๋ฐ์ดํธ๊ฐ ๋์ง ์์ต๋๋ค.
์ @Transactional ์ด ๋์ํ์ง ์์๋์ง๋ Spring ์ @Transactional ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ฐฉ์์ ๋ํด ์ดํด๋ณผ ํ์๊ฐ ์์ต๋๋ค.
# Spring @Transactonal ๊ธฐ๋ฅ์ ๊ณต ๋ฐฉ์
JPA ์ ๊ฐ์ฒด ๋ณ๊ฒฝ๊ฐ์ง๋ transacton ์ด commit ๋ ๋, ์๋ํฉ๋๋ค.
๊ทธ๋ ๊ธฐ์ Spring ์ @Transactonal ์ด๋ ธํ ์ด์ ์ ์ ์ธํ ๋ฉ์๋๊ฐ ์คํ๋๊ธฐ์ , transaction begin ์ฝ๋๋ฅผ ์ฝ์ ํ๋ฉฐ
๋ฉ์๋๊ฐ ์คํ๋ ํ, transaction commit ์ฝ๋๋ฅผ ์ฝ์ ํ์ฌ, ๊ฐ์ฒด ๋ณ๊ฒฝ๊ฐ์ง๋ฅผ ์ํํ๊ฒ ์ ๋ํฉ๋๋ค.
Spring ์ ์ฝ๋ ์ฝ์ ๋ฐฉ๋ฒ์ ํฌ๊ฒ 2๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
- ๋ฐ์ดํธ ์ฝ๋ ์์ฑ (CGLIB ์ฌ์ฉ)
- ํ๋ก์ ๊ฐ์ฒด ์ฌ์ฉ
2๊ฐ์ง ๋ฐฉ๋ฒ์ค Spring ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ก์ ๊ฐ์ฒด ์ฌ์ฉ ์ด ์ ํ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ์ interface ๊ฐ ๋ฐ๋์ ํ์ํฉ๋๋ค.
SpringBoot ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฐ์ดํธ ์ฝ๋ ์์ฑ ์ด ์ ํ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ์, ๊ตณ์ด interface ๊ฐ ํ์์์ต๋๋ค.
๋ง์ฝ ๊ฐ๋ฐํ๊ฒฝ์ด SpringBoot ๋ผ๋ฉด Books ์ธํฐํ์ด์ค ์์ด ๋ด๋ ๋ฌด๋ฐฉํฉ๋๋ค.
์๋ฆฌ๋ ์ด๋ ์ต๋๋ค. ํ๋ก์ ๊ฐ์ฒด๋ก ์ฐ๋ฆฌ๊ฐ ๋ง๋ ๋ฉ์๋๋ฅผ ํ๋ฒ ๊ฐ์ธ์, ๋ฉ์๋ ์ ์๋๋ก ์ฝ๋๋ฅผ ์ฝ์ ํด์ค๋๋ค.
public class BooksProxy {
private final Books books;
private final TransactonManager manager = TransactionManager.getInstance();
public BooksProxy(Books books) {
this.books = books;
}
public void addBook(String bookName) {
try {
manager.begin();
books.addBook(bookName);
manager.commit();
} catch (Exception e) {
manager.rollback();
}
}
}
๊ทธ๋ ๊ธฐ์, ์ฐ๋ฆฌ๋ BooksImpl ์๋ฃํ์ ์ฌ์ฉ ํ ๋, ์คํ๋ง์ด ์ ๊ณตํ๋ BooksProxy ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉฐ,
BooksProxy ๊ฐ์ฒด๊ฐ ์ ๊ณตํ๋ addBook ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ผ๋ง transaction ์ฒ๋ฆฌ๊ฐ ์ํ๋๋๊ฒ์ ๋๋ค.
# @Transactonal ์ด ์ํ๋์ง ์์ ์ด์ .
๋ค์ ์๋์ ์์ ๋ฅผ ์ดํด๋ด ๋๋ค.
public class BooksImpl implements Books {
public void addBooks(List<String> bookNames) {
bookNames.forEach(bookName -> this.addBook(bookName));
}
@Transactional
public void addBook(String bookName) {
Book book = new Book(bookName);
bookRepository.save(book);
book.setFlag(true);
}
}
BooksProxy ๊ฐ addBooks ๋ฉ์๋๋ฅผ ์ํํ๋ฉด, ์๋์ ๊ฐ์ ์์๋ก ์๋๋ฉ๋๋ค.
BooksProxy::addBooks -> BooksImpl::Book
์ฆ, BooksImpl ๋ด๋ถ์ ์ฝ๋(addBook) ๊ฐ ์ํ ๋๊ธฐ ๋๋ฌธ์ ํด๋น ๋ฉ์๋๋ ํ๋ก์๋ก ๊ฐ์ธ์ง ๋ฉ์๋๊ฐ ์๋๋ผ๋ ์ ์์
@Transactonal ์ด๋ ธํ ์ด์ ๊ธฐ๋ฅ์ด ์ํ๋์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค.
# ํด๊ฒฐ๋ฐฉ๋ฒ
์ฌ์ค @Transactional ๋ฉ์๋๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ์ง ์๋๊ฒ์ด ๊ทผ๋ณธ์ ์ธ ํด๊ฒฐ์ฑ ์ ๋๋ค.
ํ์ง๋ง ๋ง์ฝ ๊ตณ์ด ์ฌ์ฉํด์ผ ๊ฒ ๋ค๋ฉด, ์์กด์ฑ ์ฃผ์ ์ ์ด์ฉํ์ฌ Proxy ์ธ์คํด์ค๋ฅผ ์์ฒด์ ์ผ๋ก ๊ฐ์ ธ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
@Service
public class BooksImpl implements Books {
@Autowired
private Books self;
public void addBooks(List<String> bookNames) {
bookNames.forEach(bookName -> self.addBook(bookName)); // this ๊ฐ ์๋ ๋ณ์ self ๋ก
}
@Transactional
public void addBook(String bookName) {
Book book = new Book(bookName);
bookRepository.save(book);
book.setFlag(true);
}
}
ํด๋น ์ฝ๋๋ Books ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํ์ฌ BooksProxy ์ธ์คํด์ค๋ฅผ ์ฃผ์ ํ ์ ์๋๋ก ์ ๋ํฉ๋๋ค.
์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด, ์ํ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค. @Autowired ๋ก๋ง ํด์ฃผ์ธ์. Autowired ์ซ๋ค.
๊ทธ ํ, ์๊ธฐ ์์ ์ฆ this ๊ฐ ๊ฐ์ง๊ณ ์๋ ์์ํ addBook ๋ฉ์๋๊ฐ ์๋๋ผ proxy ๋ก ๊ฐ์ธ์ง addBook ๋ฉ์๋๋ฅผ ํตํด@Transactional ์ด๋ ธํ ์ด์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
# ์ ๋ฆฌํ์๋ฉด
@Transactonal ์ด๋ ธํ ์ด์ ๋ฉ์๋๋ ํด๋์ค ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ์ง ๋ง๊ณ , ๋ฐ์์ ์ฌ์ฉํ์. (ํ๋ก์ ๊ฐ์ฒด ๋๋ฌธ์) ๊ตณ์ด ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด, ์๊ธฐ ์์ ์ Proxy ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ฒ๋ฆฌํ์.
์ถ์ฒ: https://mommoo.tistory.com/92 [๊ฐ๋ฐ์๋ก ํ๋ก ์๊ธฐ]