こんにちは!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開発ライフがよりスマートで楽しいものになることを応援しています!
