์ ๋ถ ์ฑ๊ณตํ๊ฑฐ๋, ์๋๋ฉด ์์ ์๋ ์ผ๋ก ํ๊ฑฐ๋ (All or Nothing)
ํธ๋์ ์
์ด๋ (Transaction)
- ๋ ์ด์ ์ชผ๊ฐค ์ ์๋ ์
๋ฌด์ ์ต์ ๋จ์๋ฅผ ์๋ฏธํจ.
- ๊ฒฝ์ ํ๋์์์ ํธ๋์ ์
์ด๋, "๊ฐ์น ์๋ ๋ฌด์ธ๊ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ์ฝ์์ด๋ ์ฌ๊ฑด"์ ๋ปํจ.
- ๊ฐ์น์ ๊ตํ: ๋์ ์ฃผ๊ณ ์ปคํผ๋ฅผ ๋ฐ๊ฑฐ๋, ์๋น์ค๋ฅผ ์ด์ฉํ๊ณ ๋น์ฉ์ ์ง๋ถํ๋ ํ์
- ๊ธฐ๋ก์ ์์ฑ: ์์์ฆ, ์ธ๋ณด์ด์ค, ์ํ ๋ช
์ธ์ ์ฒ๋ผ "์ด๋ฐ ์ผ์ด ์์๋ค" ๋ ์ฆ๊ฑฐ(๊ธฐ๋ก)๋ฅผ ๋จ๊น.
- ์ฌ๋ฌด์ ์ํฅ: ๋์ด ์ค๊ฐ์ผ๋ ํ๊ณ ์ฅ๋ถ์ "์
๊ธ(debit)" ์ด๋ "์ถ๊ธ(credit)" ์ผ๋ก ๊ธฐ๋ก ๋์ด์ผ ํจ.
์ปดํจํฐ & ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์์ ์๋ฏธ
- ์ฌ๋ฌ ๋จ๊ณ์ ์์
์ ํ๋์ ๋ฉ์ด๋ฆฌ๋ก ๋ฌถ์ด์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ์๋ฏธ
ํธ๋์ ์
ํต์ฌ ์์น 4๊ฐ์ง (ACID)
- ์์์ฑ (Atomicity)
- ์ฑ๊ณตํ๋ ค๋ฉด 100% ๋ค ์ฑ๊ณตํด์ผ ํ๊ณ , ํ๋๋ผ๋ ์คํจํ๋ฉด 0% ์ผ๋ก ๋๋๋ ค์ผ ํ๋ค.
- ex) ๊ณ์ข์ด์ฒด : A ๊ฐ B ์๊ฒ 1๋ง์ ์ก๊ธํ ๋, A ๊ณ์ข์์ ์ถ๊ธํ B ๊ณ์ข ์
๊ธ ์คํจํ๋ ๊ฒฝ์ฐ ๋ ๋ค ์์ํ๋ก ๋๋๋ ค์ผํจ.
- ์ผ๊ด์ฑ (Consistency)
- ๋ฐ์ดํฐ๋ ์ธ์ ๋ ์ ํด์ง ๊ท์น(์ ์ฝ ์กฐ๊ฑด)์ ์ง์ผ์ผ ํ๋ค
- ์๋ฏธ: ํธ๋์ ์
์ด ์ฑ๊ณต์ ์ผ๋ก ๋๋๊ณ DB ์ ๊ท์น์ ๋ณํจ์์ด ์ ์ง ๋์ด์ผ ํ๋ค.
- ๊ณ ๋ฆฝ์ฑ (Isolation)
- ์ฌ๋ฌ ์์
์ด ๋์์ ์ผ์ด๋๋ ์๋ก ๋ฐฉํดํ์ง ์๋๋ค
- ์๋ฏธ: ์ฌ๋ฌ ํธ๋์ ์
์ด ๋์์ ์คํ๋ ๋, ๋ง์น ๊ฐ๊ฐ ํผ์์ ์คํ๋๋๊ฒ์ฒ๋ผ ๊ฒฉ๋ฆฌ๋์ด์ผ ํ๋ค.
- ์์
์ด ์งํ ์ค์ผ๋ ๋ค๋ฅธ ์์
์ด ๊ทธ ์ค๊ฐ ๊ณผ์ ์ ๋ค์ฌ๋ค๋ณด๊ฑฐ๋ ๊ฑด๋๋ฆด ์ ์์.
- ์ง์์ฑ (Durability)
- ์ฑ๊ณตํ ๊ธฐ๋ก์ ์ ๋๋ก ์ฌ๋ผ์ง์ง ์๋๋ค.
- ์๋ฏธ: ํธ๋์ ์
์ด ์ผ๋จ "์ฑ๊ณต(commit)"์ผ๋ก ๋๋๋ฉด, ๊ทธ ๊ฒฐ๊ณผ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๊ตฌ์ ์ผ๋ก ๊ธฐ๋ก๋จ.
- ์ดํ ์์คํ
์ฅ์ ๊ฐ ๋๊ฑฐ๋ ์ ์์ด ๊บผ์ง๋๋ผ๋, ๊ธฐ๋ก์ ์์ ํ๊ฒ ๋ณด์กด๋จ.
ํธ๋์ ์
์์
- ์ํฉ
- ์ ์ ๊ฐ ๋ค์ ๋ก๊ทธ์ธ ํ๋ฉด์ refresh token ์ ์๋ก ๋ฐ๊ธ ๋ฐ์.
- ์ด๋ ๊ธฐ์กด ํ ํฐ์ ์ญ์ ํ ์ฌ๋ฐ๊ธ ๋ฐ์ ํ ํฐ์ ์ ์ฅํด์ผํจ.
- ์ด๋ฅผ ํธ๋์ ์
์ผ๋ก ๊ตฌํํ๋๋ก ํ๋ค.
// 1. ํธ๋์ ์
๊ตฌํ ์ (before)
// 1)๊ธฐ์กด Refresh Token ์ญ์
await this.refreshTokenRepository.delete({ user_uuid: user.uuid });
// 2) ์๋ก์ด refresh token ์ ์ฅ
await this.refreshTokenRepository.save({
user_uuid: user.uuid,
token_hash: refreshTokenHash,
expired_at: new Date(refreshTokenExpiresAt), // Date ๊ฐ์ฒด๋ก ๋ณํํ์ฌ TIMESTAMPTZ์ ์ ์ฅ
});
// 2. ํธ๋์ญ์
๊ตฌํ ํ
// ํ์ ์์กด์ฑ: import { DataSource } from 'typeorm'; //
await this.dataSource.transaction(async (transactionalEntityManager) => {
// 1) ๊ธฐ์กด Refresh Token ์ญ์
// ์ฃผ์: ํธ๋์ญ์
๋ด๋ถ์์๋ ๋ฐ๋์ 'transactionalEntityManager'๋ฅผ ์ฌ์ฉํด์ผ ํจ๊ป ๋ฌถ์
๋๋ค.
await transactionalEntityManager.delete(UserRefreshToken, {
user_uuid: user.uuid
});
// 2) ์๋ก์ด refresh token ์ ์ฅ
await transactionalEntityManager.save(UserRefreshToken, {
user_uuid: user.uuid, // ํ๋๋ช
์ DB ์ค๊ณ์ ๋ง์ถฐ user_uuid๋ก ํต์ผํ์ต๋๋ค.
token_hash: refreshTokenHash,
expired_at: new Date(refreshTokenExpiresAt),
});
});