여러 변경을 하나의 업무 작업으로 묶고 실패 시 취소합니다.
트랜잭션은 관련 변경이 전부 성공하거나 모두 취소되게 합니다. Service의 업무 메서드가 경계를 소유하고 repository가 같은 transaction context를 사용해야 합니다.
외부 API와 사용자 대기를 transaction 안에 두지 않아 lock 시간을 짧게 유지합니다.
deadlock과 serialization failure는 idempotency를 고려해 제한적으로 재시도합니다.
첫 변경 뒤 예외를 삼키고 성공 응답을 보내면 데이터 일관성이 깨집니다.
로컬 프로젝트에서 확인해보세요잔액보다 큰 이체에서 rollback 결과가 유지되는지 바꾸어 확인하세요.
import "reflect-metadata";
import { Controller, Get, Injectable, Module } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
@Injectable()
class TransferService {
private balances = { a: 100, b: 50 };
transfer(amount: number) {
const before = { ...this.balances };
try {
if (amount > this.balances.a) throw new Error("잔액 부족");
this.balances.a -= amount;
this.balances.b += amount;
return { ok: true, balances: this.balances };
} catch (error) {
this.balances = before;
return { ok: false, message: (error as Error).message, balances: this.balances };
}
}
}
@Controller()
class AppController {
constructor(private readonly service: TransferService) {}
@Get() home() {
return this.service.transfer(120);
}
}
@Module({ controllers: [AppController], providers: [TransferService] })
class AppModule {}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(4173, "0.0.0.0");
}
bootstrap();