こんにちは!Access VBAの開発現場へようこそ。
マクロの記録から一歩抜け出して、「自分の手でシステムをコントロールしたい!」と熱意を持っているあなたなら、きっと今日のテーマは最高にワクワクする内容になるはずです。
今回は、複数人でAccessを使うときに避けて通れない「データの排他制御」、その核心であるDAOの `LockEdits`(ロックエディッツ)プロパティについて徹底的に解説します。
ここをクリアすれば、データが意図せず書き換わってしまう恐怖から解放され、実務で通用する堅牢なアプリケーションが作れるようになりますよ。さあ、一緒に扉を開けましょう!
—
1. なぜ「レコードロック」が必要なのか?
想像してみてください。あなたがAccessの画面で顧客の電話番号を書き換えているまさにその瞬間、別のフロアの営業担当者も同じ顧客のデータを編集し、保存ボタンを押しました。
…さて、どちらの変更が残るべきでしょうか?
そのままでは、後から保存した人のデータで上書きされてしまい、先ほど入力した大切な変更が消えてしまいますよね。こうした「データの競合」を防ぐ仕組みがレコードロックです。
Access(DAO)では、このロックの方式をVBAで完全にコントロールできます。それが `LockEdits` プロパティです。
—
2. 悲観的排他制御 vs 楽観的排他制御
まずは、この世界を支配する2つの思想を知っておきましょう。ここが今日の最重要ポイントです。
① 悲観的排他制御(Pessimistic Locking)
- 思想:「誰もがデータを書き換えるかもしれない。疑わしきはロックせよ!」
- 動き: レコードを「編集しよう」と`Edit`メソッドを実行した瞬間から、他の人はそのレコードを触れ(編集でき)なくなります。自分が`Update`するまで独占状態です。
- メリット: データの整合性が100%守られます(上書き事故が絶対に起きない)。
- デメリット: 自分が長く画面を開いている間、他の人が待ちぼうけを食らうため、同時操作性が悪くなります。
② 楽観的排他制御(Optimistic Locking)
- 思想:「滅多に同時編集なんて起きないさ。保存するときにだけ確認しよう!」
- 動き: 編集している最中は、誰もロックしません。みんな自由に触れます。ただし、「さあ保存しよう」と`Update`した瞬間に、自分が読み込んでから他の人がデータを書き換えていないかをチェックし、書き換わっていればエラーにします。
- メリット: 同時操作性が高く、スムーズにシステムが使えます。
- デメリット: 競合(コンフリクト)が起きたときの例外処理を自分でコードに書く必要があります。
Access VBAのDAOでは、レコードセットを開くとき、あるいは編集するときに、この2つを自由に行き来できます。
—
3. 実践!VBAコードで LockEdits を使い分ける
それでは、実際のコードを見てみましょう。先輩エンジニアとして、現場でそのまま使える実用的な書き方を伝授します。
パターンA:確実に守る「悲観的ロック」の書き方
お金の計算やステータス変更など、絶対に他の人と同時に触られたくない重要データを扱う場合は、悲観的ロック(`dbEditPessimistic`)を採用します。
Sub UpdateStatus_Pessimistic()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
‘ 顧客ID「C001」のレコードを取得
Set rs = db.OpenRecordset(“SELECT FROM T_顧客 WHERE 顧客ID = ‘C001′”, dbOpenDynaset)
If Not rs.EOF Then
‘ 【重要】ここで悲観的ロックを明示的にかける
rs.Edit
rs!LockEdits = True ‘ True = 悲観的排他制御
‘ データの更新
rs!ステータス = “優良顧客”
rs!最終更新日 = Now
‘ 保存(Updateの瞬間にロックが解除される)
rs.Update
MsgBox “データを安全に更新しました!”, vbInformation
Else
MsgBox “対象のデータが見つかりません。”, vbExclamation
End If
‘ クリーンアップ
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
> 💡 先輩からのアドバイス:
> 悲観的ロック中に他のユーザーがそのレコードを開こうとすると、ロックが解除されるまでVBAの処理が一時停止(またはエラー)します。そのため、画面を開きっぱなしにするような用途には絶対に使わないでくださいね。
—
パターンB:実務の主流「楽観的ロック」の書き方
通常の大規模な業務システムや、多くの人が一斉にアクセスするマスターメンテナンスなどでは、楽観的ロック(`dbEditOptimistic`)が好まれます。
Sub UpdateMemo_Optimistic()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset(“SELECT FROM T_顧客 WHERE 顧客ID = ‘C001′”, dbOpenDynaset)
On Error GoTo ErrorHandler
If Not rs.EOF Then
rs.Edit
rs!LockEdits = False ‘ False = 楽観的排他制御(デフォルトもこれです)
rs!メモ = “本日の面談完了。次回提案あり。”
‘ 【ここがポイント】
‘ Updateの瞬間に他人がデータを書き換えてい実行時エラー(例: エラー3186や3218など)が発生します
rs.Update
MsgBox “メモを保存しました!”, vbInformation
End If
CleanUp:
On Error Resume Next
rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
‘ 楽観的ロック特有の競合エラーをキャッチ
If Err.Number = 3186 Or Err.Number = 3218 Then
MsgBox “他のユーザーがこのデータを既に変更しています。” & vbCrLf & _
“一度画面を閉じ直して、最新のデータを確認してください。”, vbCritical, “排他制御エラー”
Else
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
End If
‘ 競合時は変更をキャンセルしてレコードを元の状態に戻す
rs.CancelUpdate
Resume CleanUp
End Sub
—
4. 陥りやすい罠とエラー対策
初心者の頃によくやってしまう失敗パターンをいくつか共有しておきます。ここを知っておくだけで、デバッグの時間が何時間も浮きますよ!
罠①:トランザクションとの混同
「トランザクション(`BeginTrans` / `CommitTrans`)」と「レコードロック(`LockEdits`)」は似て非なるものです。
- トランザクション: 複数のテーブルや複数のレコードに対する変更を「全部まとめて成功させるか、全部なかったことにするか(原子性)」の仕組み。
- レコードロック: 同時アクセスされたときの「ぶつかり合いを防ぐ」仕組み。
※実務では、楽観的ロックとトランザクションを組み合わせて、より堅牢なシステムを構築します。
罠②:開くときの形式(`dbOpenTable` vs `dbOpenDynaset`)
`LockEdits` プロパティを自由に変更して細やかな制御を行いたい場合、レコードセットは必ず `dbOpenDynaset`(ダイナセット) または `dbOpenSnapshot` で開く必要があります。テーブル直接(`dbOpenTable`)では制限が多いので注意してください。
—
まとめ:ここをクリアすれば、Access VBAの基本はバッチリです!
お疲れ様でした!今回は `LockEdits` プロパティを通じて、Accessにおける排他制御の概念を紐解きました。
- 悲観的ロック(`True`): 「絶対に他に触らせない!」確実性重視。
- 楽観的ロック(`False`): 「保存時に確認するよ!」同時性・速度重視。
業務の要件(誰が、どれくらいの頻度で、どこを編集するのか)に合わせてこの2つを適切に使い分けられるようになれば、あなたはもう「マクロの初心者」ではありません立派なAccessアプリケーション・アーキテクトです。
現場の要件に合わせたスマートなコードで、周囲をあっと言わせるシステムを作ってみてくださいね。応援しています!
