このプロジェクトはサービスレイヤーにトランザクションを実装します。
MVC パターンのアーキテクチャでは、リポジトリがすべてのデータベース関連のタスクを含み、サービス/Usecase がビジネスロジックを含みます。
あるプロジェクトのエンドポイントが、多くのデータベーステーブルにエフェクトを生成するとします。そのような場合、これらのデータベースアクションの 1 つが失敗すると、対応するデータベーステーブルには他のデータが保存されません。そこで、トランザクションは他のテーブルがデータベースに保存されないようにするテクニックを提供します。
人気のある ORM ライブラリであるGormは、このトランザクション機能を提供しています。
Gorm トランザクションの基本例を以下に示します:
// トランザクションを開始する
tx := db.Begin()
// トランザクションの中でいくつかのデータベース操作を行う (ここからは 'db' ではなく 'tx' を使用する)
tx.Create(...)
// ...
// エラーの場合はトランザクションをロールバックする
tx.Rollback()
// あるいはトランザクションをコミットする
tx.Commit()
これは最も基本的なトランザクションで、リポジトリ層のメソッド内部で使用できます。
例えば、商品を購入する際、商品価格がユーザー残高から差し引かれ、商品在庫も商品テーブルから差し引かれます。これは商品を購入する際の単純なビジネスロジックです。
この 2 つのテーブルのトランザクションを、リポジトリ内の 1 つの purchaseProduct()
メソッドで行えば、SOLID の原則 の単一責任の法則を排除することができます。
また、テストケースの作成も難しくなります。このプロセスはビジネスで必要なロジックなので、この purchaseProduct()
はサービスレイヤーに置くべきです。このメソッドの内部では、データベースに関連する部分を実行するために、2 つの異なるリポジトリメソッド reduceStockAmount()
と reduceBalance()
を呼び出します。
サービスレベルにはデータベースロジックが含まれておらず、サービスメソッド内で別々のリポジトリメソッドが呼び出されるため、最初のセクションの例で見たようなトランザクションをサービス内で設定することはできません。このため、ミドルウェアを作成する必要があります。
このファイルには、サービス層レベルでトランザクションを管理するための UoW (Unit of Work) ミドルウェアを作成するためのコードが含まれています。