DAOでのレコードロックと排他制御の徹底解説【Access/VBA上級者向け】

Access

こんにちは、なかぜんです。

Accessをマルチユーザーで運用していると、こんなお悩みありませんか?

  • 「突然『他のユーザーが編集中です』というエラーが出て保存できない」
  • 「排他エラーが怖くてVBAでの更新処理が組めない」
  • 「どのロックレベルを選べばよいのか分からない」

こうしたトラブルを防ぐ鍵は、DAOによる適切なレコードロックと排他制御にあります。

この記事では、DAOによる排他制御の基本から、エラー処理付きの実践的なコード、そして応用テクニックまでを、Access/VBA上級者向けにやさしく、かつ業務で役立つように解説していきます。

1. DAOでのレコードロックの基本をおさらい

DAOとは?

DAO(Data Access Objects)は、Accessが標準で持つデータ操作用オブジェクトモデルで、ローカル/共有DBの細やかな制御が得意です。

ロックタイプの種類

  • dbOptimistic:実際に .Update が呼ばれるまでロックされない(最も一般的)
  • dbPessimistic:レコード取得時にロック(他ユーザーの更新を防ぐ)
  • dbReadOnly:読み取り専用

2. 実践:排他制御を意識した更新処理のコード例

基本的な更新コード(dbPessimistic使用)

Sub UpdateWithLock()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    On Error GoTo ErrHandler

    Set db = CurrentDb()
    Set rs = db.OpenRecordset("T_商品マスタ", dbOpenDynaset, dbPessimistic)

    rs.FindFirst "商品コード = 'A001'"
    If Not rs.NoMatch Then
        rs.Edit
        rs!商品名 = "高級チョコレート"
        rs.Update
        MsgBox "更新完了しました!"
    Else
        MsgBox "該当レコードが見つかりませんでした。"
    End If

ExitHandler:
    rs.Close: Set rs = Nothing
    Set db = Nothing
    Exit Sub

ErrHandler:
    MsgBox "エラーが発生しました:" & Err.Description
    Resume ExitHandler
End Sub

ポイント:

  • dbPessimisticを指定することで、他のユーザーによる同時編集をブロック
  • 更新前にFindFirstで対象レコードを特定
  • エラー時には必ずオブジェクト解放処理を

3. よくあるトラブルと対処法

「他のユーザーがレコードをロック中」の対処

このエラーは、対象レコードが既に誰かによりEditされている状態で発生します。VBAで対策するには以下のような工夫が必要です:

  • Try-Catch的にOn Error Resume Nextで編集可能かチェック
  • ロック検出時は数秒待って再試行(リトライ制御)

リトライ付きの例

Sub UpdateWithRetry()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim i As Integer
    Const RETRY_LIMIT = 3
    Const WAIT_MS = 1000
    On Error GoTo ErrHandler

    Set db = CurrentDb()

    For i = 1 To RETRY_LIMIT
        Set rs = db.OpenRecordset("T_商品マスタ", dbOpenDynaset, dbPessimistic)
        rs.FindFirst "商品コード = 'A001'"

        If Not rs.NoMatch Then
            On Error Resume Next
            rs.Edit
            If Err.Number = 0 Then
                rs!商品名 = "新しい商品名"
                rs.Update
                MsgBox "更新成功"
                Exit For
            Else
                MsgBox "ロック中、再試行します…(" & i & "回目)"
                Err.Clear
                Sleep WAIT_MS ' APIでスリープ(別途宣言必要)
            End If
        End If
        rs.Close: Set rs = Nothing
    Next

ExitHandler:
    On Error Resume Next
    If Not rs Is Nothing Then rs.Close: Set rs = Nothing
    Set db = Nothing
    Exit Sub

ErrHandler:
    MsgBox "エラー発生:" & Err.Description
    Resume ExitHandler
End Sub

4. 排他制御を活かす応用テクニック

フォームの連動更新時の排他対策

サブフォームや複数画面で同一レコードを扱う場合、自作のロック制御を用いる方法もあります。

  • ロック状態を別テーブルで管理(例:T_ロック管理)
  • 更新時に対象レコードの排他権を先取り

「ロック管理テーブル」例

Sub CheckLockBeforeUpdate()
    If DCount("*", "T_ロック管理", "商品コード='A001'") > 0 Then
        MsgBox "他のユーザーが編集中です。"
        Exit Sub
    End If

    ' ロック取得
    CurrentDb.Execute "INSERT INTO T_ロック管理 (商品コード, ユーザー名) VALUES ('A001', 'なかぜん')"
    ' 更新処理実施...

    ' 最後にロック解除
    CurrentDb.Execute "DELETE FROM T_ロック管理 WHERE 商品コード='A001'"
End Sub

5. まとめと次のステップ

今回は、DAOでのレコードロックと排他制御について、次の内容を学びました。

  • DAOのロックモード(Optimistic/Pessimistic)の違い
  • 排他エラーを防ぐコード例と対策
  • リトライ処理やロック管理テーブルを活用した応用テクニック

Accessのマルチユーザー環境では、レコードロックの理解がトラブル防止のカギになります。ぜひ、ご自身のシステムにも取り入れてみてください。

それでは、またお会いしましょう。なかぜんでした😊