6/2 ドメイン駆動設計Chapter10 10-4 10-4-1
10-4 トランザクションによる防衛
- トランザクションは一貫した状態を保つために、相互依存的な操作の完了ないし取り消しを保証します
- 通販サイトで商品を購入するときにポイントを使うとします
- システムはまずユーザの使用しようとしたポイントを減らします
- 注文しようとした商品の在庫がなくなっていたら処理は失敗します
- ポイントは減りますが、標品は注文されず、発送もされません
- 注文しようとした商品の在庫がなくなっていたら処理は失敗します
- トランザクションはこのような場合に、途中で不正終了をしても、ポイントを減らさないようにできます
- システムはまずユーザの使用しようとしたポイントを減らします
- 通販サイトで商品を購入するときにポイントを使うとします
10-4-1 トランザクションを取り扱うパターン
トランザクションを利用すれば、ユーザ登録処理の問題は解決しそうです
import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); class UserRegisterCommand { constructor(public id: string, public name: string) {} } class UserApplicationService { constructor(private readonly userRepository: IUserRepository, private readonly userService: UserService) {} async register(command: UserRegisterCommand): Promise<void> { const userId = new UserId(command.id); const userName = new UserName(command.name); const user = new User(userId, userName); // トランザクションの開始 await prisma.$transaction(async () => { if (await this.userService.exists(user)) { throw new Error("ユーザはすでに存在しています。"); } await this.userRepository.save(user); }); // トランザクションの終了 } }
このコードでは、Prismaの$transaction
メソッドを使用してトランザクションを開始し、その中でユーザーの存在チェックと保存を行っています。もしユーザーがすでに存在していた場合はエラーをスローし、トランザクションがロールバックされます。ユーザーが存在しない場合は、ユーザーが保存され、トランザクションがコミットされます。