ํธ๋์ญ์
์ด๋ ์ฌ๋ฌ ์์
์ ์งํํ๋ค๊ฐ ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๊ฒฝ์ฐ ์ด์ ์ํ๋ก ๋กค๋ฐฑํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ฒ์ ๋งํฉ๋๋ค.
๋ ์ด์ ์ชผ๊ฐค ์ ์๋ ์ต์ ์์
๋จ์์ด๋ฉฐ, commit์ผ๋ก ์ฑ๊ณตํ๊ฑฐ๋ ๋๋ rollback์ผ๋ก ์คํจ ์ดํ ์ทจ์ ๋์ด์ผ ํฉ๋๋ค.
๐ก Transaction ACID
- ์์์ฑ Atomicity: ํธ๋์ญ์
๋ด์ ์์
๋ค์ ๋ชจ๋ ์ฑ๊ณต ๋๋ ๋ชจ๋ ์คํจํ๋ค.
- ์ผ๊ด์ฑ Consistency: ๋ชจ๋ ํธ๋์ญ์
์ ์ผ๊ด์ฑ ์๋ DB ์ํ๋ฅผ ์ ์งํ๋ค. (ex: DB์ ๋ฌด๊ฒฐ์ฑ ์ ์ฝ ์กฐ๊ฑด ํญ์ ๋ง์กฑ)
- ๊ฒฉ๋ฆฌ์ฑ Isolation: ๋์์ ์คํ๋๋ ํธ๋์ญ์
๋ค์ ์๋ก ์ํฅ์ ๋ฏธ์น์ง ์๋๋ค. (ex: ๋์์ ๊ฐ์ ๋ฐ์ดํฐ ์์ X)
- ์ง์์ฑ Durability: ํธ๋์ญ์
์ด ์ฑ๊ณต์ ์ผ๋ก ๋๋๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋ ํญ์ ๊ธฐ๋ก๋์ด์ผ ํ๋ค.
์คํ๋ง์ ํธ๋์ญ์
๊ด๋ จ 3๊ฐ์ง ํต์ฌ ๊ธฐ์ ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
ํธ๋์ญ์
๋๊ธฐํ๋ ํธ๋์ญ์
์ ์์ํ๊ธฐ ์ํ Connection ๊ฐ์ฒด๋ฅผ ํน๋ณํ ์ ์ฅ์์ ๋ณด๊ดํด๋๊ณ ํ์ํ ๋ ๊บผ๋ด์ธ ์ ์๋๋ก ํ๋ ๊ธฐ์ ์
๋๋ค.
JDBC๋ฅผ ์ด์ฉํ๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ฌ๋ฌ ๊ฐ์ ์์
์ ํ๋์ ํธ๋์ญ์
์ผ๋ก ๊ด๋ฆฌํ๋ ค๋ฉด Connection ๊ฐ์ฒด๋ฅผ ๊ณต์ ํ๋ ๋ฑ ๋ถํ์ํ ์์
๋ค์ด ์๊ธธ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ๋๊ธฐํ ์ ์ฅ์๋ ์์
์ค๋ ๋๋ง๋ค Connection ๊ฐ์ฒด๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ์ถฉ๋์ด ๋ฐ์ํ์ง ์๋๋ก ํฉ๋๋ค.
// ๋๊ธฐํ ์์
TransactionSynchronizeManager.initSynchronization();
Connection c = DataSourceUtils.getConnection(dataSource);
... // ์์
์งํ
// ๋๊ธฐํ ์ข
๋ฃ
DataSourceUtils.releaseConnection(c, dataSource);
TransactionSynchronizeManager.unbindResource(dataSource);
TransactionSynchronizeManager.clearSynchronization();
ํ์ง๋ง JDBC๊ฐ ์๋ Hibernate์ ๊ฐ์ ๊ธฐ์ ์ ์ด๋ค๋ฉด
Spring์ ํธ๋์ญ์
๊ธฐ์ ์ ๊ณตํต์ ์ ๋ด์ ํธ๋์ญ์
์ถ์ํ ๊ธฐ์ ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค.
์ด๋ฅผ ์ด์ฉํจ์ผ๋ก์จ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ ๊ธฐ์ ๋ง๋ค(JDBC, JPA, Hibernate ๋ฑ) ์ข
์์ ์ธ ์ฝ๋๋ฅผ ์ด์ฉํ์ง ์๊ณ ๋ ์ผ๊ด๋๊ฒ ํธ๋์ญ์
์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํด์ฃผ๊ณ ์์ต๋๋ค.
Spring์ด ์ ๊ณตํ๋ ํธ๋์ญ์
๊ฒฝ๊ณ ์ค์ ์ ์ํ ์ถ์ ์ธํฐํ์ด์ค๋ PlatformTransactionManager์
๋๋ค.
์๋ฅผ ๋ค์ด ๋ง์ฝ JDBC์ ๋ก์ปฌ ํธ๋์ญ์
์ ์ด์ฉํ๋ค๋ฉด DataSourceTxManager๋ฅผ ์ด์ฉํ๋ฉด ๋ฉ๋๋ค.
์ด๋ก์จ ์ฌ์ฉํ๋ ๊ธฐ์ ๊ณผ ๋ฌด๊ดํ๊ฒ PlatformTransactionManager๋ฅผ ํตํด ๋ค์์ ์ฝ๋์ ๊ฐ์ด ํธ๋์ญ์
์ ๊ณต์ ํ๊ณ , ์ปค๋ฐํ๊ณ , ๋กค๋ฐฑํ ์ ์๊ฒ ๋ฉ๋๋ค.
public Object invoke(MethodInvoation invoation) throws Throwable {
TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
Object ret = invoation.proceed();
this.transactionManager.commit(status);
return ret;
} catch (Exception e) {
this.transactionManager.rollback(status);
throw e;
}
}
Spring์์๋ ๋ง์น ํธ๋์ญ์
์ฝ๋์ ๊ฐ์ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ฝ๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ธฐ ์ํด
ํด๋น ๋ก์ง์ ํด๋์ค ๋ฐ์ผ๋ก ๋นผ๋ด์ ๋ณ๋์ ๋ชจ๋๋ก ๋ง๋๋ AOP(Aspect Oriented Programming, ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ)๋ฅผ ๊ณ ์ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
์ด๋ฅผ ์ ์ฉํ ํธ๋์ญ์
์ด๋
ธํ
์ด์
(@Transactional)์ ์ง์ํ๊ฒ ๋์๋ค. ์ด๋ฅผ ์ ์ฉํ๋ฉด ์์ ๊ฐ์ ์ฝ๋๋ฅผ ํต์ฌ ๋น์ง๋์ค ๋ก์ง๋ง ๋ค์๊ณผ ๊ฐ์ด ๋จ๊ธธ ์ ์์ต๋๋ค.
@Service
@RequiredArgsConstructor
@Transactional
public class UserService {
private final UserRepository userRepository;
public void addUsers(List<User> userList) {
for (User user : userList) {
if (isEmailNotDuplicated(user.getEmail())) {
userRepository.save(user);
}
}
}
}