【入門編】【上級】DAO.Recordsetの「LockEdits」プロパティによる、悲観的排他制御と楽観的排他制御の使い分け – Access VBA解析バイブル

スポンサーリンク

こんにちは!Access VBAの世界へようこそ。
マクロの記録から一歩踏み出し、「自分でプログラムをコントロールしたい!」という熱意を持つあなたへ、今日はとてもエキサイティングなお話をしますね。

ここをクリアすれば、Access VBAの基本はバッチリですよ!

テーマは、複数人が同時に使うシステムで避けて通れない「レコードの排他制御(LockEditsプロパティ)」です。
「同時に入力したらデータが消えちゃった!」「なんだかシステムがやけに重い……」そんな現場の悲劇を防ぐための、プロの知見をたっぷりお伝えします。

1. なぜ「排他制御」が必要なの?(現実世界との比喩)

想像してみてください。
会社に1冊しかない「売上台帳」が、共有の机の上に置いてあります。

  • パターンA:早い者勝ちの無法地帯

あなたが台帳に書き込んでいる最中に、隣の同僚が突然その台帳を引っパチッて、別の数字を書き込んでしまいました。あとで見返したら、あなたの苦労した記入が上書きされて消えている……これが「データの競合」です。

  • パターンB:厳重な鍵付き管理

あなたが台帳を開いた瞬間、その台帳ごと金庫に閉じ込め、他の人はあなたが閉じきるまで1文字も触らせない。これが「悲観的排他制御」です。安全だけど、みんなが待ちぼうけを食らいますよね。

  • パターンC:自己責任の信用スタイル

みんな自由に台帳を見書きするけれど、レジの締め(保存する瞬間)に「あれ、さっきとデータ変わってない?」と確認し、変わっていたら「ちょっと待った!」とやり直させる。これが「楽観的排他制御」です。

Access VBAの世界でも、この「鍵をどうかけるか」をコントロールするのが `LockEdits` プロパティなんです。

2. LockEditsプロパティの正体:悲観 vs 楽観

DAOの `Recordset` を開くとき、Accessはデフォルトで「安全第一」の動きをします。これをコードで自由自在に操るのが `LockEdits` です。

  • `dbOptimistic` (楽観的排他制御 / 値:1)
  • 思想: 「まあ、同時には被らないっしょ!」
  • 動き: レコードを開くときは鍵をかけません。データを「書き込もう(Updateしよう)とする瞬間」に初めて他の人に書き換えられていないかチェックします。
  • メリット: パフォーマンスが落ちず、複数人がサクサク作業できます。
  • `dbPessimistic` (悲観的排他制御 / 値:2)
  • 思想: 「人間は裏切る。絶対に俺が書き換えるまでは触らせん!」
  • 動き: レコードを編集状態(`Edit`メソッド)にした瞬間から、そのレコードにガッチリ鍵(ロック)をかけます。他の人は編集どころか閲覧すら待たされることがあります。
  • メリット: データの整合性は100%守られますが、長時間開いたままにするとシステム全体が重くなります。

3. 実践!コードで見る排他制御の書き方

百聞は一見に如かず。実際のVBAコードを見てみましょう。
今回は、受注テーブルのステータスを安全に更新する処理を書いてみます。

パターン1:サクサク動かす「楽観的ロック」の実装例

Sub UpdateStatus_Optimistic()
Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb

‘ 【重要】LockEditsに dbOptimistic を指定(楽観的)
‘ レコードを開く時点ではロックしません
Set rs = db.OpenRecordset(“T_受注”, dbOpenDynaset, , dbOptimistic)

On Error GoTo ErrorHandler

rs.FindFirst “受注ID = 1005”

If Not rs.NoMatch Then
rs.Edit ‘ ここで編集モードへ
rs!ステータス = “出荷完了”

‘ 更新(Update)の瞬間に、他人がこのデータを改変していないかチェックされる
rs.Update
MsgBox “データを正常に更新しました!(楽観的)”, vbInformation
Else
MsgBox “対象のデータが見つかりませんでした。”, vbExclamation
End If

CleanUp:
‘ オブジェクトの解放はプロの基本
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub

ErrorHandler:
‘ 楽観的ロックで競合が発生した場合のエラー番号は 3186 または 3218 など
If Err.Number = 3186 Or Err.Number = 3218 Then
MsgBox “他のユーザーがこのデータを既に変更しています。” & vbCrLf & _
“画面を最新の状態に更新して、やり直してください。”, vbCritical, “競合エラー”
Else
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
>End If
Resume CleanUp
End Sub

パターン2:絶対にミスが許されない「悲観的ロック」の実装例

銀行の残高引き落としや、在庫数が残り1個のチケット予約など、「絶対に他の奴に割り込まれたくない!」という時に使います。

Sub UpdateStock_Pessimistic()
Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb

‘ 【重要】LockEditsに dbPessimistic を指定(悲観的)
‘ 開くとき、あるいはEditする瞬間からレコードをロックします
Set rs = db.OpenRecordset(“T_在庫”, dbOpenDynaset, , dbPessimistic)

On Error GoTo ErrorHandler

rs.FindFirst “商品ID = ‘A-001′”

If Not rs.NoMatch Then
rs.Edit ‘ ★この瞬間にレコードに強力なロックがかかる!

‘ 在庫を1減らす
rs!在庫数 = rs!在庫数 – 1

rs.Update ‘ Updateするまで、他のユーザーはこのレコードを触れない
MsgBox “在庫を引き当てました!(悲観的)”, vbInformation
End If

CleanUp:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub

ErrorHandler:
‘ 悲観的ロックの場合、既に他の人がロックしていればエラーになる
If Err.Number = 3260 Then
MsgBox “現在、他のユーザーがこの在庫データを編集中です。” & vbCrLf & _
“しばらく待ってから再度お試しください。”, vbExclamation, “ロック中”
Else
MsgBox “エラー: ” & Err.Description, vbCritical
End If
Resume CleanUp
End Sub

4. 現場で陥りがちな「罠」とエンジニアの知見

ここで、Access VBAを使いこなす上で絶対に知っておくべき「現場の罠」をいくつかシェアします。これを知っているだけで、ワンランク上のエンジニアになれます。

1. 画面(フォーム)を開きっぱなしにするユーザー問題
悲観的ロック(`dbPessimistic`)をかけたまま、ユーザーがトイレに行ってしまったらどうなるでしょう? その間、他の人は誰もそのデータを変更できず、システムがフリーズしたような状態になります。
【対策】 基本的には楽観的ロック(`dbOptimistic`)を基本とし、どうしても排他が必要な瞬間(トランザクション処理内など)だけ短時間でロックをかける設計にしましょう。
2. トランザクション(DBEngine.BeginTrans)との組み合わせ
複数のテーブルを同時に更新する場合は、単体の `LockEdits` だけでなく、トランザクションを組み合わせるのがプロの作法です。「すべて成功するか、すべて無かったことにするか」の担保には、DAOのトランザクションが不可欠です。
3. カレントDBの罠
フォームの裏で動くレコードセットや、単発のバッチ処理では `CurrentDb.OpenRecordset` を使いますが、長時間の接続や巨大なループを回す際は、変数に `Database` オブジェクトをしっかり格納してメモリリークを防ぎましょう(上記のサンプルコードはその形に準拠しています)。

まとめ

いかがでしたでしょうか?

  • 基本は「楽観的 (`dbOptimistic`)」でサクサクと!
  • 絶対にデータを死守したいクリティカルな場面だけ「悲観的 (`dbPessimistic`)」を検討する!

この使い分けができるようになると、パフォーマンスとデータの整合性が両立した、実務で愛される頑健なAccessシステムが作れるようになります。

ここをクリアしたあなたなら、もう「初心者」のラベルは卒業です。ぜひ実際の開発現場でこのコードを試してみてくださいね。あなたのAccess開発ライフがよりスマートで楽しいものになることを応援しています!

タイトルとURLをコピーしました