1. @Transactional
@Transactional ์ด๋ ธํ ์ด์ ์ ํน์ method์ ํธ๋์ญ์ ์ ์ ์ฉํ ์ ์๊ฒ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋์ญ์ ์ ํ ์์ฑ, ๊ฒฉ๋ฆฌ ์์ค, timeout, read-only, rollback conditions์ ์ค์ ํ ์ ์๋๋ก ํฉ๋๋ค.
1.1 @Transactional ๋์ ๋ฐฉ์
์คํ๋ง์ ํธ๋์ญ์ ๊ฒฝ๊ณ์ค์ ๊ณผ ๊ฐ์ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์ ์ฉํ๊ธฐ ์ํด Proxy๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ฐ์ดํธ ์ฝ๋ ์กฐ์๊ณผ ๊ฐ์ ๋ณต์กํ ๊ธฐ์ ์ ์ด์ฉํฉ๋๋ค.
1.2 @Transactional ์ฌ์ฉ๋ฒ
interface, class์ ์ ์ธ๋ถ ๋๋ method ์ ์ธ๋ถ์ ์ง์ ํด๋น ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
interface, class์ ์ ์ธ๋ถ์ ์ฌ์ฉ๋ ๊ฒฝ์ฐ public method์ ํธ๋์ญ์ ์ด ์ ์ฉ๋๋ฉฐ, private ๋๋ protected method์ ์ง์ @Transactional ์ด๋ ธํ ์ด์ ์ ์ค์ ํ๋๋ผ๋ ์คํ๋ง์ ์ด๋ฅผ ๋ฌด์ํฉ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก @Transactional
์ด๋
ธํ
์ด์
์ interface ์ ์ธ๋ถ์ ์ค์ ํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ Spring Data Repository Interface(@Repository
)๋ก ์ค์ ๋ interface์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@Transactional
public interface UserService {
void add(User user);
}
2. ํธ๋์ญ์ ์ ํ(Transaction Propagation)
2.1 ํธ๋์ญ์ ์ด๋?
๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์ (Database Transaction)์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ฆฌ ์์คํ ๋๋ ์ ์ฌํ ์์คํ ์์ ์ํธ์์ฉ์ ๋จ์์ด๋ค. ์ฌ๊ธฐ์ ์ ์ฌํ ์์คํ ์ด๋ ํธ๋์ญ์ ์ด ์ฑ๊ณต๊ณผ ์คํจ๊ฐ ๋ถ๋ช ํ๊ณ ์ํธ ๋ ๋ฆฝ์ ์ด๋ฉฐ, ์ผ๊ด๋๊ณ ๋ฏฟ์ ์ ์๋ ์์คํ ์ ์๋ฏธํ๋ค.
์ด๋ก ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์คํ ์ ๊ฐ๊ฐ์ ํธ๋์ญ์ ์ ๋ํด ์์์ฑ(Atomicity), ์ผ๊ด์ฑ(Consistency), ๋ ๋ฆฝ์ฑ(Isolation), ์๊ตฌ์ฑ(Durability)์ ๋ณด์ฅํ๋ค. ์ด ์ฑ์ง์ ์ฒซ๊ธ์๋ฅผ ๋ฐย ACID๋ผ ๋ถ๋ฅธ๋ค. ๊ทธ๋ฌ๋, ์ค์ ๋ก๋ ์ฑ๋ฅํฅ์์ ์ํด ์ด๋ฐ ํน์ฑ๋ค์ด ์ข ์ข ์ํ๋๊ณค ํ๋ค.
์ด๋ค ์์คํ ๋ค์์๋ ํธ๋์ญ์ ๋ค์ ๋ ผ๋ฆฌ์ ์์ ๋จ์(LUW, Logical Units of Work)๋ก ๋ถ๋ฆฐ๋ค. [์ํค๋ฐฑ๊ณผ]
2.2 ํธ๋์ญ์ ์ ํ๋?
ํธ๋์ญ์ ๊ฒฝ๊ณ์์ ์ด๋ฏธ ์งํ ์ค์ธ ํธ๋์ญ์ ์ ์ ๋ฌด์ ๋ฐ๋ผ ์ด๋ป๊ฒ ๋์ํ ๊ฒ์ธ๊ฐ๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐฉ์์ ๋๋ค. ์คํ๋ง์ ์ ํ ์์ฑ์ ์ฐธ์กฐํ์ฌ ํธ๋์ญ์ ์ ์์ํ๊ณ ์ผ์ ์ค์งํฉ๋๋ค.
2.3 ํธ๋์ญ์ ์ ํ ์์ฑ
-
PROPAGATION_REQUIRED(
DefaultTransactionDefinition
): default ์ ํ ์์ฑ์ด๋ฉฐ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค. ๋ถ๋ชจ ํธ๋์ญ์ ์ด ์์ผ๋ฉด ์๋ก ์์ํ๊ณ , ์์ผ๋ฉด ์ฐธ์ฌํฉ๋๋ค.
์ฝ๋๋ฅผ ์งํํ๋ ์ค์ ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, ์งํ ์ฌํญ์ด ๋ชจ๋ Rollback ๋ฉ๋๋ค.@Transactional(propagation = Propagation.REQUIRED) public void requiredMethod(String s) { ... } @Transaction public void requiredMethod(String s) { ... }
-
PROPAGATION_SUPPORTS: ๋ถ๋ชจ ํธ๋์ญ์ ์ด ์์ผ๋ฉด ์ฐธ์ฌํ๊ณ , ์์ผ๋ฉด ํธ๋์ญ์ ์์ด ๋์ํฉ๋๋ค.
@Transaction(propagation = Propagation.SUPPORTS) public void supportsMethod(String s) { ... }
-
PROPAGATION_MANDATORY: ๋ถ๋ชจ ํธ๋์ญ์ ์ด ์์ผ๋ฉด ์ฐธ์ฌํ๊ณ , ์์ผ๋ฉด ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค.
@Transactional(propagation = Propagation.MANDATORY) public void mandatoryMethod(String s) { ... }
-
PROPAGATION_NEVER: ํธ๋์ญ์ ์ ํ์ฉํ์ง ์์ผ๋ฉฐ, ๋ถ๋ชจ ํธ๋์ญ์ ์ด ์์ผ๋ฉด ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค.
@Transactional(propagation = Propagation.NEVER) public void neverMethod(String s) { ... }
-
PROPAGATION_NOT_SUPPORTED: ํธ๋์ญ์ ์ด ์์ผ๋ฉด, ๋จผ์ ์คํ๋ง์ ํธ๋์ญ์ ์ ์ผ์ ์ค์งํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํธ๋์ญ์ ์์ด ๋น์ฆ๋์ค ๋ก์ง์ ์คํํฉ๋๋ค.
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void notSupportedMethod(String user) { ... }
-
PROPAGATION_REQUIRES_NEW: ํญ์ ์๋ก์ด ํธ๋์ญ์ ์ ์์ํฉ๋๋ค. ์ฝ๋๋ฅผ ์งํํ๋ ์ค์ ์์ธ๊ฐ ๋ฐ์(Rollback)ํ๋๋ผ๋ ๊ฐ๊ฐ์ ํธ๋์ญ์ ์ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
@Transactional(propagation = Propagation.REQUIRES_NEW) public void requiresNewMethod(String user) { ... }
-
PROPAGATION_NESTED: ๋ถ๋ชจ ํธ๋์ญ์ ์ด ์์ผ๋ฉด, ๋จผ์ Savepoint๋ฅผ ํ์ํ๊ณ ์ค์ฒฉ ํธ๋์ญ์ ์ ์์ํฉ๋๋ค. ์ค์ฒฉ ํธ๋์ญ์ ์์ Rollback์ด ๋ฐ์ํ๋ฉด Savepoint๋ก ๋์๊ฐ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ถ๋ชจ ํธ๋์ญ์ ์ด Commit ๋ ๋ ํจ๊ป Commit ๋ฉ๋๋ค. ๋ง์ฝ ํธ๋์ญ์ ์ด ์์ผ๋ฉด PROPAGATION_REQUIRED์ฒ๋ผ ๋์ํฉ๋๋ค.
@Transactional(propagation = Propagation.NESTED) public void nestedMethod(String user) { ... }
3. ๊ฒฉ๋ฆฌ์์ค (Transaction Isolation)
์๋ฒ ํ๊ฒฝ์์๋ ๋ง์ ์์ ํธ๋์ญ์ ์ด ์งํ๋ ์ ์์ต๋๋ค. ๊ฐ๊ฐ์ ํธ๋์ญ์ ์ ๋ ๋ฆฝ์ ์ผ๋ก ์์๋๋ก ์ฒ๋ฆฌํ๋ฉด ์ข๊ฒ ์ง๋ง, ์ฑ๋ฅ์ด ํฌ๊ฒ ๋จ์ด์ง๋๋ค. ๋ฐ๋ผ์ ์ ์ ํ ๊ฒฉ๋ฆฌ์์ค์ ์ค์ ํ์ฌ ๊ฐ๋ฅํ ๋ง์ ํธ๋์ญ์ ์ ๋์์ ์ฒ๋ฆฌํ๋ฉด์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ํด์ผํฉ๋๋ค. ๊ฒฉ๋ฆฌ์์ค์ ๊ธฐ๋ณธ์ ์ผ๋ก DB์ ์ค์ ๋์ด ์์ง๋ง JDBC ๋๋ผ์ด๋ฒ๋ DataSource์์ ๋ค์ ์ค์ ํ ์ ์์ต๋๋ค.
3.1 ๊ฒฉ๋ฆฌ์์ค์ ๋ฐ๋ผ ๋ฐ์ํ ์ ์๋ Side Effects (๋ฐ์ดํฐ ๋ถ์ ํฉ)
-
Dirty read: ์งํํ๊ณ ์๋ ํธ๋์ญ์ ์ ์ปค๋ฐ๋์ง ์์ ๋ณ๊ฒฝ์ ์กฐํํ ์ ์๋ ๋ฌธ์ ์ ๋๋ค.
-
Nonrepeatable read: ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ์กฐํํ์ ๋ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ์กฐํ๋๋ ๋ฌธ์ ์ ๋๋ค. ๋์์ ์งํ๋๋ ํธ๋์ญ์ ์ด ๋์ผํ Row๋ฅผ Update & Commit ํ ๋ ๋ฐ์ํฉ๋๋ค.
-
Phantom read: ํน์ ๋ฒ์๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ๋ฅผ ๋ค์ ์คํํ ๋ ๊ฒฐ๊ณผ Row ์๊ฐ ๋ฌ๋ผ์ง๋ ๋ฌธ์ ์ ๋๋ค. ๋ค๋ฅธ ํธ๋์ญ์ ์ด ํด๋น ๋ฒ์์ ์ํ๋ ํ์ ์ถ๊ฐ ๋๋ ์ ๊ฑฐํ๊ณ Commit ํ ๋ ๋ฐ์ํฉ๋๋ค.
3.2 ๊ฒฉ๋ฆฌ์์ค์ ์ข ๋ฅ
-
READ_UNCOMMITTED: ๊ฐ์ฅ ๋ฎ์ ๋ ๋ฒจ์ ๊ฒฉ๋ฆฌ์์ค์ ๋๋ค. Commit ๋์ง ์์ ๋ณ๊ฒฝ์ ๋ค๋ฅธ ํธ๋์ญ์ ์ด ์กฐํํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ ๋ถ์ ํฉ ๋ฐ์ ์ํ์ด ๋์ง๋ง ์ฑ๋ฅ์ด ๊ฐ์ฅ ์ฐ์ํฉ๋๋ค. Oracle, Postgres์์ ์ง์ํ์ง ์์ต๋๋ค.
@Transactional(isolation = Isolation.READ_UNCOMMITTED) public void log(String m) { ... }
- ๋ฐ์ํ ์ ์๋ Side Effects:
- Dirty read
- Non-Repeatable read
- Phantom read
- ๋ฐ์ํ ์ ์๋ Side Effects:
-
READ_COMMITTED: Second Level ๊ฒฉ๋ฆฌ์์ค์ ๋๋ค. Commit ๋ ๋ฐ์ดํฐ๋ง ์กฐํํ ์ ์์ผ๋ฉฐ, Dirty read๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. Postgres, SQL Server, Oracle์์ default ๊ฒฉ๋ฆฌ์์ค์ ๋๋ค.
@Transactional(isolation = Isolation.READ_COMMITTED) public void log(String m) { ... }
- ๋ฐ์ํ ์ ์๋ Side Effects:
- Nonrepeatable read
- Phantom read
- ๋ฐ์ํ ์ ์๋ Side Effects:
-
REPEATABLE_READ: Third Level ๊ฒฉ๋ฆฌ์์ค์ ๋๋ค. ํธ๋์ญ์ ์ด ์์๋์ง ์ ์ ์ปค๋ฐ๋ ๋ฐ์ดํฐ๋ง ์ ๊ทผํ ์ ์์ต๋๋ค. Dirty read, Non-Repeatable read๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. MySQL์์ default ๊ฒฉ๋ฆฌ์์ค์ด๋ฉฐ, Oracle์์ ์ง์ํ์ง ์์ต๋๋ค.
@Transactional(isolation = Isolation.REPEATABLE_READ) public void log(String m) { ... }
- ๋ฐ์ํ ์ ์๋ Side Effects:
- Phantom read
- ๋ฐ์ํ ์ ์๋ Side Effects:
-
SERIALIZABLE: ๊ฐ์ฅ ์๊ฒฉํ ๊ฒฉ๋ฆฌ์์ค์ ๋๋ค. ํธ๋์ญ์ ์ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ ํ ๋ฐ์ดํฐ ๋ถ์ ํฉ๋ ๋ฐ์ํ์ง ์์ง๋ง, ๋์ ์ฒ๋ฆฌ ์ฑ๋ฅ์ด ๋งค์ฐ ๋จ์ด์ง๋๋ค.
@Transactional(isolation = Isolation.SERIALIZABLE) public void log(String m) { ... }
4. ์ ํ์๊ฐ
ํธ๋์ญ์ ์ ์ํํ๋ ๋ฐ ์ ํ์๊ฐ์ ์ค์ ํ ์ ์์ต๋๋ค. PROPAGATION_REQUIRED๋ PROPAGATION_REQUIRES_NEW์ ํจ๊ป ์ฌ์ฉํ ๋ ์๋ฏธ๊ฐ ์์ต๋๋ค.
5. ์ฝ๊ธฐ์ ์ฉ (Read Only)
์ฝ๊ธฐ์ ์ฉ์ผ๋ก ์ค์ ํ ๊ฒฝ์ฐ ํธ๋์ญ์ ๋ด์์ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ๋ ์๋๋ฅผ ๋ง์ ์ ์์ต๋๋ค.
References
https://www.baeldung.com