Access VBAの「ロック」を制する者はマルチユーザーを制す:DAO.Recordsetの排他制御、極限の設計指針
多くのAccess開発者が陥る罠がある。「とりあえず動くから」と、デフォルトの排他制御設定を放置することだ。だが、マルチユーザー環境でその甘さは、いずれ「書き込みエラー」という名の悪夢となって帰ってくる。
今日は、DAO.Recordsetの`LockEdits`プロパティを軸に、「悲観的排他制御」と「楽観的排他制御」をどう使い分け、堅牢な業務アプリを構築するかを、プロの視点で伝授する。
—
1. なぜ「排他制御」の理解が不可欠なのか
Accessのバックエンド(Jet/ACEエンジン)における排他制御には2つの流派がある。
- 悲観的排他制御 (Pessimistic Locking): レコードを開いた瞬間にロックをかける。競合は絶対に起こらないが、他人の作業を止め、システム全体を低速化させる。
- 楽観的排他制御 (Optimistic Locking): 更新する直前までロックしない。競合が発生した時に初めてエラーを検知する。スケーラビリティは高いが、衝突時のハンドル(例外処理)が必須となる。
結論から言おう。 現代の業務アプリにおいて、無闇な悲観的ロックは「悪」だ。しかし、会計データのような厳密性が求められる箇所では必要になる。この使い分けをコードレベルで設計できるか否かが、エンジニアとしての格を決める。
—
2. 実践:DAO.Recordsetによる排他制御の制御
以下のコードは、保守性を担保しつつ、排他制御を明示的に切り替えるためのテンプレートだ。
‘ @description: 堅牢な排他制御を実装したDAO更新テンプレート
‘ @param: strSQL – 更新対象のクエリ
‘ @param: isPessimistic – Trueなら悲観的、Falseなら楽観的
Public Sub UpdateRecordSecure(strSQL As String, isPessimistic As Boolean)
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
‘ 楽観的排他制御: dbOpenDynasetのデフォルトはdbOptimistic
‘ 悲観的排他制御: dbPessimisticを指定
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset, , IIf(isPessimistic, dbPessimistic, dbOptimistic))
On Error GoTo ErrorHandler
If Not (rs.BOF And rs.EOF) Then
rs.Edit
rs!Status = “Processed”
rs.Update ‘ ここで確定(楽観的の場合はこの瞬間に競合チェック)
End If
CleanExit:
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
If Err.Number = 3186 Or Err.Number = 3218 Then ‘ ロックエラーの代表例
MsgBox “現在、他者がこのレコードを編集しています。後でもう一度試してください。”, vbCritical
Else
MsgBox “予期せぬエラー: ” & Err.Description, vbCritical
End If
Resume CleanExit
End Sub
このコードの「プロのこだわり」
- IIfによる動的切り替え: ロックモードを引数で制御することで、ビジネスロジックに応じた柔軟な運用を可能にしている。
- 明示的な定数: `dbPessimistic` / `dbOptimistic` を明示的に指定することで、コードを読む他者が「この箇所が排他制御のホットスポットである」と直感的に理解できるようにしている。
- エラーハンドラの分離: 単なるエラーログではなく、排他エラー(3186/3218)を特定し、ユーザーに適切なアクションを促す仕様にしている。
—
3. 現場で生き残るための「鉄則」
① 「フォーム」と「VBAコード」の排他設定を混同するな
Accessのフォームには「レコードロック」プロパティがあるが、これはフォーム単位の設定だ。一方、VBAの`Recordset`は、プログラムが能動的に制御する「データベースの心臓部」である。プログラムで複雑な更新を行う場合は、フォームの設定をアテにせず、常にVBA側で排他制御を定義すること。
② 悲観的ロックは「短く」保て
悲観的ロックをかけている最中に、ユーザーへのメッセージボックス表示や、外部ファイルへの長時間出力を行ってはならない。ロックしたまま処理を中断すると、それはデッドロック(システム停止)への直行便だ。
③ 楽観的ロックは「例外処理」が全て
楽観的ロックを採用するなら、`Update`メソッドが失敗する確率を0にはできないことを前提とせよ。「更新失敗→競合発生→ユーザーへ現状データを再読み込みさせる」というフローを、例外処理の中に美しく組み込むことが、真に堅牢なプロダクションコードの姿だ。
—
最後に:エンジニアへの提言
Accessは「誰でも使える」ツールだが、プロの手にかかれば「エンタープライズ級のバックエンド」を隠し持った強力な武器に変貌する。
今回解説した排他制御の使い分けは、単なる知識ではなく、「多人数が同時に触るデータ」に対する敬意である。ユーザーが安心してデータを入力できる環境を作ることこそが、我々エンジニアの真の付加価値だ。
まずは、今書いているそのコードの`OpenRecordset`を見直してほしい。そこに、あなたのエンジニアとしての魂を刻み込んでくれ。
