-
[Spring/SpringBoot] νΈλμμ μ΄λ? μ€νλ§μ Transactional(feat: AOP)π»Programming/SpringBoot 2023. 9. 25. 00:05
νΈλμμ (Transaction)μ΄λ?
: DB μνλ₯Ό λ³νμν€λ νλμ λ Όλ¦¬μ κΈ°λ₯μ μννκΈ° μν μμ μ λ¨μ.
= μͺΌκ°€ μ μλ μ¬λ¬ μμ λ€μ λ Όλ¦¬μ μΌλ‘ μ΅μ λ¨μλ‘ λ¬Άμ κ²
νΈλμμ μ μμ μν©
μ¨λΌμΈ μΌνλͺ°μ κ²°μ ν λ, λκ°μ§ μμ μ κ±°μ³μΌνλ€.
1. ν맀μ²μ λμ 보λ΄κΈ°
2. ν맀μ²μμ κ³ κ°μ΄ λ³΄λΈ λμ λ°κΈ°
μ λ μμ μ΄ ν νΈλμμ μ΄λΌκ³ νμ. μ΄ κ²½μ° κ³ κ°μ΄ ν맀μ²μ λμ 보λλλ° ν맀μ²μμ κ³ κ°μ΄ λ³΄λΈ λμ λ°μ§ λͺ»νλ κ²½μ°λ, κ³ κ°μ΄ λμ 보λ΄μ§ μμλλ° ν맀μ²μμ λμ λ°λ κ²½μ°κ° μκΈ°λ©΄ μλλ€. λͺ¨λ μμ μ΄ μ±κ³΅μ μΌλ‘ μλ£λμ΄μΌ μμ κ²°κ³Όλ₯Ό μ μ©(commit)νκ³ , νΈλμμ μ μν λͺ¨λ μμ μ€μ(1λ²μ΄λ 2λ² λμ€μ) νλλΌλ μ€λ₯κ° λ°μνλ κ²½μ°μλ μμ μ μ€ννκΈ° μ μ μνλ‘ μλ²½νκ² λμκ°μΌ νλ κ²(rollback)μ΄ νΈλμμ μ κ°λ μ΄λ€.
νΈλμμ μ νΉμ§(Transaction ACID)
"A"tomicity(μμμ±)
: νΈλμμ μ μ°μ°μ DBμ λͺ¨λ λ°μλκ±°λ, λͺ¨λ λ°μλμ§ μμμΌνλ€. νλλΌλ μ€ν¨νλ€λ©΄, μμ μ±κ³΅ν κ²λ€μ 볡ꡬμμΌμΌνλ€.
"C"onsistency(μΌκ΄μ±)
: νΈλμμ μ μμ μ²λ¦¬ κ²°κ³Όλ νμ μΌκ΄μ± μμ΄μΌ νλ€. = λͺ¨λ νΈλμμ μ μΌκ΄μ± μλ DB μνλ₯Ό μ μ§νλ€.(ex: DBμ λ¬΄κ²°μ± μ μ½ μ‘°κ±΄ νμ λ§μ‘±)
"I"solation(격리μ±)
: μ΄λ€ νΈλμμ λ λ€λ₯Έ νΈλμμ μ μμ μ λΌμ΄λ€κ±°λ μλ‘ μν₯μ μ€ μ μλ€. (ex: λμμ κ°μ λ°μ΄ν° μμ X)
"D"urability(μ§μμ±)
: νΈλμμ μ΄ μλ£λλ€λ©΄, κ²°κ³Όλ μꡬμ μ΄μ΄μΌνλ€.
* 격리μ±μ μλ²½νκ² λ³΄μ₯νλ €λ©΄ νΈλμμ μ μμλ₯Ό μ ν΄μ νλμ© μ€νν΄μΌνλλ°, μ±λ₯μ΄ λ무 λλΉ μ§κΈ° λλ¬Έμ νΈλμμ 격리 μμ€μ΄ μ‘΄μ¬.
νΈλμμ 격리 μμ€(Isolation Level)
λΉμ¦λμ€ λ‘μ§κ³Ό νΈλμμ μ²λ¦¬ λ‘μ§μ΄ λμμ μ‘΄μ¬νλ€λ©΄ μ½λμ μ€λ³΅μ΄ λ°μν μλ μκ³ , λΉμ¦λμ€ λ‘μ§μλ§ μ§μ€λ μ½λλ₯Ό μμ±νκΈ° μ΄λ ΅λ€. μ΄λ κ² λΉμ¦λμ€ λ‘μ§μλ§ μ§μ€νκΈ° μν΄ Springμ ν¬κ² 2κ°μ§ νΈλμμ κΈ°μ μ μ§μνλ€.
1. TransactionTemplate(TransactionManagerμ μ£Όμ λ°μ μ¬μ©)
λ°μ΄ν° μ κ·Ό κΈ°μ μλ JdbcTemplate, JPAλ± μ¬λ¬κ°μ§κ° μ‘΄μ¬νλλ° μ΄ κΈ°μ λ§λ€ νΈλμμ μ μ¬μ©νλ λ°©λ²λ λ¬λΌμ§λ€. λ°λΌμ Springμμλ μ΄κ²μ κ³ λ €ν΄ νΈλμμ μ λν μΆμνλ₯Ό μ§μνλ€. PlatformTransactionManager μΈν°νμ΄μ€λ₯Ό μ΄μ©νλ©΄ λλ€. ν΄λΉ μΈν°νμ΄μ€λ μ΄ 3κ°μ§ λ©μλλ₯Ό μ 곡νλ€.
- getTransaction(): νμ¬ TransactionStatusλ₯Ό return
- commit(): λ³κ²½ λ΄μ commit
- rollback(): λ³κ²½ λ΄μ rollback
-> TransactionManager ν΄λμ€λ₯Ό μ΄μ©ν΄ κ°λ°μκ° νΈλμμ μμ/μ’ λ£ μ§μ μ λͺ μμ μΌλ‘ κ²°μ κ°λ₯.
νΈλμμ μ λ‘μ§μ μννκ³ λͺ¨λ λ‘μ§μ΄ μ±κ³΅μ μΌλ‘ μνλμμ κ²½μ°μλ λͺ¨λ κ²°κ³Όλ₯Ό DBμ μΌκ΄μ μΌλ‘ commitνκ³ , νλλΌλ μ€ν¨νλ€λ©΄ λͺ¨λ μμ μ μμ볡ꡬ(rollback)μν¨λ€.
// νλ‘κ·Έλλ°μ νΈλμμ κ΄λ¦¬ public void sendMoney(Long senderId, Long receiverId, Long value) { Connection connection = dataSource.getConnection(); connection.setAutoCommit(false); try { // νλ²μ μ²λ¦¬λμ΄μΌ νλ λ‘μ§ 1. κ³ κ°μ΄ ν맀μ²μ λ 보λ΄κΈ° 2. ν맀μ²μμ κ³ κ°μ΄ λ³΄λΈ λ λ°κΈ° connection.commit(); } catch(SQLException e) { connection.rollback(); throw new RemittanceException(); } }
- Connection ν΄λμ€: Javaμμ μ λνλ΄λ ν΄λμ€. JDBC(Java Database Connectivity) APIμ μΌλΆλ‘ μ 곡λλ©°, λ°μ΄ν°λ² μ΄μ€μμ ν΅μ μ μν ν΅μ¬ μν μ μν.
- λ°μ΄ν°λ² μ΄μ€μμ μ°κ²°
- tryλ¬Έμμ νΈλμμ μ μν μ¬λ¬ μμ λ€ λͺ¨λκ° λ¬Έμ μμ΄ μ²λ¦¬ μλ£λλ©΄, commit.
- νλμ μμ μμλΌλ μ€λ₯κ° λ°μνλ€λ©΄ catchλ¬Έμμ rollback.
- λ³΄ν΅ μ½λλ₯Ό μμ±ν λ @Transactional μ΄λ Έν μ΄μ μ μ΄μ©νμ¬ νΈλμμ μ²λ¦¬λ₯Ό ν΄μ£Όλλ°, ν μ€νΈλ₯Ό νλ κ²½μ°μ @Transactional μ΄λ Έν μ΄μ μ μ΄μ©ν΄ Testλ₯Ό ν΄μΌνλ λ©μλμ Transactionμ 무μκ° λκΈ° λλ¬Έμ 100% ν μ€νΈλ₯Ό ν΅κ³Όνλ€κ³ νκΈ΄ μ΄λ ΅λ€. μμ½ν΄μ λ§νμλ©΄ ν μ€νΈλ₯Ό ν λ μ΄λ Έν μ΄μ μ μ΄μ©νλ©΄ νΈλμμ μ κ΄λ ¨λ ν μ€νΈλ λμ§ μλλ€λ κ²μ΄λ€.
(https://velog.io/@byeongju/Spring-Transactionμ-λν-κΈ°λ³Έ-κ°λ μ λ μμΈν μ€λͺ μ΄ λμ΄μλ€.)
2. @Transactional μ΄λ Έν μ΄μ -AOPλ₯Ό 보μ₯ν΄μ€λ€!
DBμ κ΄λ ¨λ νΈλμμ μ΄ νμν ν΄λμ€ νΉμ λ©μλμ @Transactional μ΄λ Έν μ΄μ μ λ¬μμ£ΌκΈ°λ§ νλ©΄λλ€.
(+ ν΄λμ€μ λ¬λ©΄ ν΄λΉ ν΄λμ€ λ° νμ ν΄λμ€κΉμ§ μ μ©λ¨.)
@Transactionalμ ν΄λμ€μ λ©μλ λͺ¨λ μ μ© κ°λ₯νλ€. @Transactional μ΄ μ μΈλ ν΄λμ€ μμ λ©μλμ λ @Transactionalκ° μ μΈλμλ€λ©΄, λ©μλ λ 벨μ @Transactional μ μΈμ μ°μ μ μ©. (Springμ κΈ°λ³Έμ μΌλ‘ λ μ’μ λ²μλ₯Ό μ°μ μ ν΄μ€)
@Transactional public void buy(Long money) { userDao.loseMoney(money); sellerDao.gainMoney(money); }
- loseMoney λ©μλλ gainMoney λ©μλ μ€ νλλΌλ μ€ν¨νλ€λ©΄ μ 체 μμ μ μ·¨μ.
- μμ λ©μλ λͺ¨λ μ±κ³΅νλ€λ©΄ DBμ ν΄λΉ λ³κ²½ λ΄μ λ°μ.
AOP(Aspect-Oriented Programming)
μ ν리μΌμ΄μ κΈ°λ₯μ ν¬κ² ν΅μ¬ κΈ°λ₯κ³Ό λΆκ° κΈ°λ₯μΌλ‘ λλ μ μλ€.
- ν΅μ¬ κΈ°λ₯: ν΄λΉ κ°μ²΄κ° μ 곡νλ κ³ μ ν κΈ°λ₯(λΉμ¦λμ€ λ‘μ§)(ex: UserService - μ μ κ΄λ ¨ λ‘μ§)
- λΆκ° κΈ°λ₯: ν΅μ¬ κΈ°λ₯μ 보쑰νλ κΈ°λ₯(ex: λ‘κ·Έ μΆμ , νΈλμμ μ²λ¦¬ λ±)
λΆκ° κΈ°λ₯λ€μ μ¬λ¬ μ½λμμ μ¬μ¬μ©λλ κ²½μ°κ° λ§λ€. μλ₯Όλ€μ΄ TransactionManagerλ₯Ό μ΄μ©ν΄ νΈλμμ μ²λ¦¬λ₯Ό ν΄μ€λ€λ©΄ νλ²μ μ²λ¦¬λμ΄μΌ νλ μμ λ€μ΄ μλ λͺ¨λ λΉμ¦λμ€ λ‘μ§μ commit ν΄μ£Όκ³ rollbackν΄μ£Όλ μ½λλ₯Ό λ°λ³΅ν΄μ μμ±ν΄μ£Όμ΄μΌνλ€.
-> μ΄λ¬ν λΆκ° κΈ°λ₯λ€μ λΆλ¦¬νκ³ μ΄λμ μ μ©ν μ§ μ ννλ κΈ°λ₯μ ν©μ³ νλμ λͺ¨λλ‘ λ§λ κ²μ΄ Aspectμ΄λ€.
-> μ ν리μΌμ΄μ μ λ°λΌλ³Ό λ ν΅μ¬ κΈ°λ₯μ μ§μ€ν μ μλλ‘ λμμ£Όλ λͺ¨λμ΄λΌκ³ μ΄ν΄νλ©΄ μ’λ€.
=> @Transactionalμ AOPλ₯Ό μ§ν₯ν μ μλλ‘ μ€νλ§μμ μ§μν΄μ£Όλ μ΄λ Έν μ΄μ μ΄λ€.
νλ‘κ·Έλλ°μ νΈλμμ κ΄λ¦¬ vs μ μΈμ νΈλμμ κ΄λ¦¬
νλ‘κ·Έλλ°μ νΈλμμ κ΄λ¦¬(Programmatic Transaction Management)
-ex: TransactionManager, TransactionTemplate
: νΈλμμ κ΄λ ¨ μ½λλ₯Ό μ§μ μμ±νλ λ°©λ²
μ μΈμ νΈλμμ κ΄λ¦¬(Declarative Transaction Management)
-ex: @Transactional
: μ€νλ§μμ μ 곡νλ μ΄λ Έν μ΄μ μ μ μΈν΄μ£ΌκΈ°λ§ νλ©΄λλ€!
*μ₯μ : νλ‘κ·Έλλ° νΈλμμ κ΄λ¦¬μ λΉν΄ κ°νΈ
@Transactioal λμ ꡬ쑰
μ€νλ§μ νΈλμμ AOPλ @Transactionalμ μΈμνμ¬ νΈλμμ νλ‘μλ₯Ό μ μ©.
νλ‘μλ 'λ리μΈ'μ΄λΌλ λ»μΌλ‘ Aspectμ @Transactionalμ μ μ©ν ν΄λμ€ / λ©μλμΈ Targetμ μ°κ²°ν΄μ£Όλ μν
1. ν΄λΌμ΄μΈνΈκ° API νΈμΆ
2. νλ‘μ μ€ν
3. νΈλμμ μ½λ μ€ν
4. λΉμ¦λμ€ λ‘μ§ μ€ν
5. νΈλμμ μ½λ μ€ν(commit / rollback)
*μ€νλ§μμ AOPλ₯Ό ꡬννλ λ°©μμ JDK Dynamic Proxyμ CGLIBκ° μλ€. λ λ°©λ²μ μ΄λ€ κΈ°μ μ ν΅ν΄ Proxyκ°μ²΄λ₯Ό μμ±νλλμ μ°¨μ΄κ° μλλ°, λ μμΈν μ 보λ
μ μμΌλ μ°Έκ³ νλ©΄ μ’λ€.
References
'π»Programming > SpringBoot' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ