トランザクションの重要性とデータベース操作の整合性を保つ方法

トランザクションの重要性とデータベース操作の整合性を保つ方法

トランザクションとは?

トランザクションとは、一連のデータベース操作を「1つのまとまった処理」として扱う仕組みです。

データベース内で複数の操作が絡む際に、データの整合性を保つための重要な仕組みとなっています。

トランザクションで処理をすることにより、全ての操作が正常に行われた場合にのみ、変更を確定させることができます(コミット)。

また、もし途中で問題があった場合には、処理を取り消す(ロールバック)ことも可能です。

このように、トランザクション処理を行えば、データベース内の情報が一貫性を持ち、信頼性の高い情報提供が実現されます。

トランザクションの使用例

トランザクションの処理の使用例として、銀行口座からの引き出しを例とします。

銀行では、「口座残高の減少」と「引き出し金額の記録」が1つのトランザクションとして取り扱われます。

なぜなら、もし途中で問題が発生した時に、トランザクションが途中で終了した場合、引き出し金額が正しく反映されず、データが整合性を欠く可能性があるからです。

トランザクションの条件4つ

トランザクションには、以下の4つの特性(ACID特性)から、データベースの安定性と整合性を確保するための基本的な要件があります。

Atomicity(原子性)

トランザクション内のすべての操作が成功するか、すべてが取り消されるかのどちらかです。

Consistency(一貫性)

トランザクションの開始前と終了後にデータベースの整合性が保たれます。

Isolation(独立性)

複数のトランザクションが同時に実行されても互いに影響を与えません。

Durability(永続性)

トランザクションが成功した場合、その結果は永続的に保存されます。

トランザクションの結果は、特別なログに記録され、データベース障害が発生した場合でも復元可能です。その結果、データの安定性が保たれ、信頼性のある状態が維持されます。

複数のデータベース操作をまとめる方法

トランザクションが特に役立つのは、複数のデータベース操作を1つにまとめて扱う場面です。

先ほどの例で紹介したものと同様に、銀行の送金システムを考えてみましょう。

  1. 送金元の口座から金額を引き落とす。
  2. 送金先の口座に金額を加算する。

この2つの操作は独立して行うと、システムエラーが発生した場合に整合性が崩れる可能性があります。

例えば、引き落としは成功したが加算が失敗した場合、送金元の口座だけが減少し、送金先の口座は増えません。

これを防ぐために、両方の操作を1つのトランザクションにまとめます。

トランザクションの流れ

  1. トランザクションを開始
  2. 必要なデータベース操作を実行
  3. すべての操作が成功したら、トランザクションを確定(コミット)
  4. 途中でエラーが発生した場合は、すべての操作を取り消す(ロールバック)

トランザクションの実装例

以下は、TypeScriptでTypeORMを使用してトランザクションを実装する例です。

transactionメソッドを使うと、簡単にトランザクションを管理できます。

エラーが発生した場合は、トランザクション全体がロールバックされます。

import { getManager } from 'typeorm';

async function transferFunds(senderId: number, receiverId: number, amount: number) {
    const entityManager = getManager();

    await entityManager.transaction(async (transactionalEntityManager) => {
        // 送金元の口座を更新
        const senderAccount = await transactionalEntityManager.findOne(Account, senderId);
        if (!senderAccount) throw new Error('送金元の口座が見つかりません');
        senderAccount.balance -= amount;
        await transactionalEntityManager.save(senderAccount);

        // 送金先の口座を更新
        const receiverAccount = await transactionalEntityManager.findOne(Account, receiverId);
        if (!receiverAccount) throw new Error('送金先の口座が見つかりません');
        receiverAccount.balance += amount;
        await transactionalEntityManager.save(receiverAccount);
    });
}

まとめ

トランザクションは、データベース操作の整合性を保つために欠かせない仕組みです。

一連の操作をまとめることで、データの信頼性を高めることができます。

また、ORMを利用することで、トランザクションの実装が簡単になることがわかりました。

エンジニアとしてトランザクションを正しく理解し、活用することで、より安全で信頼性の高いシステムを構築できるようにしていきましょう。

Anycloudではプロダクト開発の支援を行っています

プロダクト開発をお考えの方はぜひAnycloudにご相談ください。

まずは相談する

記事を書いた人

Matsuura

エンジニア

Matsuura

Twitter

Anycloudでエンジニアしてます!主にFlutterやWebフロントをやっていて、最近はバックエンドやインフラに挑戦・苦戦中。