【Access VBA】トランザクションの死守:データ不整合を撲滅する「堅牢なエラーハンドリング」の極意
業務自動化の現場において、DAOやADOを用いたDB操作は「書いて終わり」ではない。データが更新される途中で予期せぬエラーが発生し、「半分だけデータが書き込まれた」という最悪の不整合状態を経験したことはないだろうか。
Access VBA開発において、トランザクション処理は単なる「おまじない」ではなく、システムの信頼性を担保する最後の砦だ。今日は、伝説的なアーキテクトの視点から、現場で絶対に変えてはならない「トランザクション制御の鉄則」を伝授する。
—
1. なぜ「雑なトランザクション」がバグを生むのか
多くの初学者が陥る罠は、`BeginTrans` と `CommitTrans` を書くだけで満足し、エラー発生時の「後始末」を怠ることだ。
‘ 【悪い例】これではエラー時にトランザクションが宙に浮く
DBEngine(0).BeginTrans
‘ 何らかのデータ更新処理
db.Execute “UPDATE T_Sales SET Status = 1”, dbFailOnError
DBEngine(0).CommitTrans
このコードの致命的な欠陥は、`Execute`メソッドでエラーが発生した際、トランザクションが「開いたまま」になることだ。この状態で放置されると、メモリリークやロックの解放漏れを引き起こし、最悪の場合、Accessファイルそのものの破損(カレントDBの肥大化・破壊)を招く。
—
2. 鉄則:構造化エラーハンドリングのテンプレート
プロの現場では、必ず「トランザクションの開閉を確実に制御する」ための構造化エラーハンドリングを徹底する。以下は、私が長年プロジェクトの基盤として採用している標準的な設計パターンだ。
Public Sub ExecuteTransactionSafe()
Dim ws As DAO.Workspace
Dim isTransStarted As Boolean
Set ws = DBEngine(0)
On Error GoTo ErrorHandler
‘ 1. トランザクション開始
ws.BeginTrans
isTransStarted = True
‘ 2. 業務処理(ここにメインの更新ロジックを書く)
‘ 例:複数テーブルの整合性が必要な更新
CurrentDb.Execute “UPDATE T_Orders SET Status = ‘Closed'”, dbFailOnError
CurrentDb.Execute “INSERT INTO T_History …”, dbFailOnError
‘ 3. コミット
ws.CommitTrans
isTransStarted = False
Exit Sub
ErrorHandler:
‘ 4. エラー発生時は必ずロールバック
If isTransStarted Then
ws.Rollback
End If
‘ エラーログの出力(運用上必須)
MsgBox “致命的なエラーが発生しました。処理を中断します。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical
End Sub
このコードの「設計思想」
- `isTransStarted` フラグの採用: どこでエラーが起きても、「今トランザクションが有効か」をフラグで判定する。これにより、ロールバック時の二重エラーや意図しない挙動を防ぐ。
- `dbFailOnError` の徹底: DAOの`Execute`メソッドには必ずこの定数をつけること。これがないと、エラーが発生してもVBAが処理を続行してしまう。これは「沈黙のバグ」の温床だ。
—
3. ADOとDAOの使い分け:アーキテクチャの視点
Access VBAではDAOがデフォルトだが、外部DB(SQL Server等)に接続する場合はADOを選択するケースがある。ここで重要なのは、「接続オブジェクトのライフサイクル」だ。
- DAO: Accessの内部DB(`.accdb`)を操作する際はDAOが最強だ。エンジンと密結合しているため、ローカル処理でのパフォーマンスはADOを圧倒する。
- ADO: 外部サーバー連携や、より細かい接続文字列の制御が必要な場合に使う。ADOのトランザクションは `Connection.BeginTrans` で行うが、考え方は上記コードと同じ。「開始したら必ず終了(Commit/Rollback)させる」というプロトコルを忘れてはならない。
—
4. プロダクションコードへの提言
現場で「なぜかデータがずれる」という相談を受けるたびに思うのは、多くのエンジニアが「ハッピーパス(正常系)しか想像していない」ということだ。
1. ネットワーク切断: 共有フォルダ上のDBで頻発する。
2. ユーザーによる強制終了: 処理中に×ボタンを押される。
3. 同時実行ロック: 他のユーザーが編集している。
これらは全て「異常系」ではなく「発生し得る日常」である。エラーハンドリングは、コードの付録ではない。「システムが崩壊しないための防御壁」そのものだ。
今日から実践すべきアクション
- 全ての更新処理を `BeginTrans` で囲う習慣をつける。
- `On Error GoTo` を書かないコードは「未完成」であると認識する。
- エラー発生時にユーザーに状況を伝え、正しくロールバックさせる設計を義務付ける。
このレベルの意識を持つだけで、あなたの書くVBAコードの信頼性は劇的に向上する。明日からの開発で、ぜひこの構造を標準装備してほしい。それが、「使えるツール」を作るエンジニアと、「壊れるツール」を作る者の決定的な境界線だ。
