プログラミングマガジン

プログラミングを中心にIT技術をできるだけわかりやすくまとめます。

  • ホーム
  • データベース
  • 【データベース】「排他制御」について
 
 
     
  • サーバー言語  
    • Python
    • Ruby
    • PHP
    • SQL
  •  
  • インフラ  
       
    • AWS
    •  
    • 基本
    • Git
  • Web
       
    • Web開発
    • JavaScript
    • Vue.js
    • React
  •  
  • 設計  
       
    • 実装設計
    • DB設計
  • 問い合わせ
  

【データベース】「排他制御」について

12.06

  • miyabisan2
  • コメントを書く

この記事は3分で読めます

排他制御とは?

複数人の同時アクセスでデータの不整合が生じてしまわないようにすることです。排他制御には主に下記2種類があります。

  • 楽観ロック
  • 悲観ロック

楽観ロック

「滅多なことじゃ他者による更新なんて起きないだろう」という楽観的な前提のもとにロックをかけること。なので、他者による更新が頻繁に起こることが見込まれるリソースに対しては楽観ロックは向かない。「処理が終わってから」じゃないと他者と競合していることがわからないので利用者にとってはストレスになってしまうためです。

具体的にはテーブルにロックキーを用意します。このロックキーを利用して下記の流れで制御を行います。

  1. 画面遷移時に一旦データを参照してロックキーを得る。
  2. ユーザーが画面上で更新情報を記述する。
  3. ユーザーが更新ボタンを押し、画面遷移前のバージョンと一致していたら更新処理を実施する。
  4. バージョンが一致していない場合は、登録エラーにして再度更新を促す画面に遷移させる。

ロックキーの種類

バージョン

バージョンという列を新たに作りそこで比較します。

メリット
  • 確実性が高い
  • 業務データに依存しない
デメリット
  • 新たにカラムが必要
  • 更新時にバージョンの更新が必要

タイムスタンプ

更新対象の列の更新日時を比較します。

メリット
  • 新たにカラムを追加する必要がない。
デメリット
  • 更新日時の精度が低い場合は確実性に欠ける。

全列データ

更新対象の全列のデータを比較します。カラム追加もできず、更新日時も追加できないという要件の場合はこれを選ぶしかないでしょう。

メリット
  • カラム追加が不要
  • 排他制御のために特別な更新も不要
デメリット
  • パフォーマンスが悪い

楽観ロックのSQLの流れ

楽観ロックのSQL発行においても2種類の流れがあります。どちらにもメリデメがありますが基本的には「SELECT(FOR UPDATE)→UPDATE」方式が選ばれることが多いでしょう。

SELECT(FOR UPDATE)→UDPATE

SELECTして問題ないことがわかればUPDATEします。SELECTする際に「FOR UPDATE」とつけることで他の人は更新することができなくなります。

UPDATE where バージョン=xx

メリット

SQL発行回数を減らせる。

デメリット

  • 業務チェックしてからになり、更新タイミングが後なので業務チェックが無駄になる。
  • 更新結果が0件だった場合に業務処理上の理由によるものか、ロックキーによるものかの判断が難しい。(例えば、そもそもデータがなかった場合等)

悲観ロック

楽観ロックと違って作業開始時に競合を検知することができるので利用者のストレスが減ります。悲観ロックの流れは下記のようになります。先に画面にアクセスした人が更新の権利を得ます。

  1. 作業者Aが更新画面にアクセスし、すでに誰かにロックされていないかチェックする。(SELECT FOR UPDATE)
  2. 誰かにロックされていなければ作業者Aは対象のレコードにロックをかける。
  3. 作業者Bが一覧画面を開く(もしくはすでに開いている状態ならばアクセスする)と誰かが更新中とエラーになる。
  4. 作業者Aはロックしているのが自分かどうかチェックしてロックの解放及び、データの更新処理を実施する。

なお、4でロックしているのが自分かどうかチェックする理由としては、運用等で勝手に誰かが更新している可能性があるためです。

悲観ロックの注意点

途中で更新処理をやめてしまった場合でもロックを解除状態にすることを忘れないようにすること。色々な場面が想定できます。

  • 作業者が一覧画面に戻った場合
  • 作業者が「閉じる」ボタンを押した場合
  • 作業者がログオフした場合
  • 作業者がPCをシャットダウンした場合
  • 作業者がセッションタイムアウトした場合

上記の中にはどうしようもない場合もあるので、下記のような対処法が取られたりします。

  1. 管理者がロックを解除できるような画面を用意する。
  2. 深夜のバッチで全ロックを自動で解除する。
  3. ロックしているユーザーであれば再度ロックを取得できるようにする。
  4. ユーザーのセッションタイムアウトのタイミングでそのユーザーが保持しているロックを全て解除する。
  5. 長時間ロックされている場合は自動的にロックを解除する仕組み

実際には、ロックの解除に時間をかけたくない場合がほとんどですので、1か3が採用されていることが多いでしょう。

悲観ロックで用意するテーブルの列

悲観ロックの対象のデータには下記のような列を用意することが一般的でしょう。

  • ロックしているユーザー
  • ロックの状態
  • どの端末からのアクセスか(セッションID等)

楽観ロックと悲観ロックどちらを使えば良いか?

上記内容を比べると悲観ロックのほうが優れているように思えるかもしれませんが、悲観ロックはあらゆる場合を想定して適切なロック解除スキルが求められるので実装難易度が高いです。なので、よほどの機能でない限りは現実的には楽観ロックが採用されるケースが多いです。

楽観ロックを使う場合

  • 競合があまり発生しない場合
  • やり直したとしても時間があまりかからない業務の場合

悲観ロックを使う場合

  • 複数人で更新するのが前提の場合
  • 競合でやり直しが難しい or 時間がかかる業務の場合
  • 具体的に言えば、お金の取引や重要文書の送付等の業務を複数人でやる業務はこちらを使います。

なお、実装コストは悲観ロックの方が高いということも考慮に入れておくと良いでしょう。

複雑な排他制御

同じテーブルに複数の種類の排他制御をかけてしまっているケース

同じテーブル内で数種類の排他制御が入り混じる場合があります。その場合排他制御自体が成り立たなくなるケースもあります。

  • 楽観ロック
  • 悲観ロック
  • 更新時の行ロックのみ(SELECT FOR UPDATE)

例えば、商品テーブルがあったとして、「商品名」、「在庫数」のカラムがあり在庫数はユーザーが行ロックで更新して、商品名を管理者が楽観ロックで更新した場合はただの行ロックではバージョン等は管理していないので上書きしてしまう可能性があります。

対策

「商品テーブル」と「在庫テーブル」というように、業務上で同じロックをする単位にテーブルも分割するようにすると良いでしょう。

登録処理の排他制御

更新処理は問題なく排他制御をかけることが可能だとは思いますが、登録処理も排他制御をかけたい場合もあると思います。その場合は、さらに上の階層のテーブルを作って、その上の階層のテーブルに排他制御をかけて対応しましょう。

スポンサーリンク
  • 2020 12.06
  • miyabisan2
  • コメントを書く
  • データベース
  • Tweets Twitter
  • このエントリーをはてなブックマークに追加
  • LINEで送る

関連記事

  1. 2018 04.25

    【データベース設計】バックアップと復旧(リカバリ)方法、レプリケーション、スナップショットとの違いなど

  2. 2018 04.25

    【データベース設計】採番について

  3. 2018 04.29

    【データベース設計】ハードウェアのサイジング(容量と性能)を決める。(物理設計)

  4. 2018 04.25

    【SQL】実行計画、実行計画変動リスクなど

  5. 2021 11.23

    【Redis】データ型の種類と用途、ユースケース(キャッシュ)

  6. 2020 08.13

    【DBスペシャリスト】「生産管理」業務、「発注・仕入・支払」業務

  • コメント ( 0 )
  • トラックバック ( 0 )
  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

返信をキャンセルする。

【システム開発】バリデーションのポイント

【データベース】バッチ処理の排他制御

RETURN TOP

著者プロフィール

エンジニア歴10年で過去に業務系、Webデザイン、インフラ系なども経験あります。現在はWeb系でフロントエンド開発中心です。

詳細なプロフィールはこちら

スポンサーリンク

カテゴリー

  • Android
  • AngularJS
  • API
  • AWS
  • C++
  • CSS
  • cursor
  • C言語
  • DDD
  • DevOps
  • Django
  • Docker
  • Figma
  • Git
  • GitLab
  • GraphQL
  • gRPC
  • Hasura
  • Java
  • JavaScript
  • Kubernetes
  • Laravel
  • linux
  • MySQL
  • Next.js
  • nginx
  • Node.js
  • NoSQL
  • Nuxt.js
  • Oracle
  • PHP
  • Python
  • React
  • Redux
  • Rspec
  • Ruby
  • Ruby on Rails
  • Sass
  • Spring Framework
  • SQL
  • TypeScript
  • Unity
  • Vue.js
  • Webサービス開発
  • Webデザイン
  • Web技術
  • インフラ
  • オブジェクト指向
  • システム開発
  • セキュリティ
  • その他
  • データベース
  • デザインパターン
  • テスト
  • ネットワーク
  • プログラミング全般
  • マイクロサービス
  • マイクロソフト系技術
  • マルチメディア
  • リファクタリング
  • 副業
  • 未分類
  • 業務知識
  • 生成AI
  • 設計
  • 関数型言語
RETURN TOP

Copyright ©  プログラミングマガジン | プライバシーポリシー