【テクニカル・上級編】トランザクション処理の鉄則:BeginTransからCommitTransまでの正しいエラーハンドリング – Access VBA解析バイブル

スポンサーリンク

Access VBAの深淵:DAO/ADOトランザクションにおける「不可逆の悲劇」を回避する唯一の解

Access VBAで「なんとなく」トランザクションを組んでいないか?
`BeginTrans`を書き、`CommitTrans`で締める。その間でエラーが起きれば`Rollback`する。教科書通りの実装だが、現場で遭遇する「謎のデータ不整合」や「ロックの解放漏れ」の9割は、この構造の甘さから生まれている。

今日は、DAOとADOのアーキテクチャの差異を理解し、メモリとプロセスを掌握した状態で、「絶対にデータ壊さない」ためのトランザクション・アーキテクチャを伝授する。

—

1. DAOとADO:トランザクションの「重み」の違い

まず前提を共有しよう。DAOはAccessのネイティブな心臓部であり、ワークスペース単位でトランザクションを管理する。対してADOはOLE DBを経由し、接続単位で管理される。

  • DAOの癖: `DBEngine(0).BeginTrans`は、現在のワークスペース全体をロックする。複数のレコードセットを操作する場合、同じワークスペース内であることを保証しなければ、意図せぬネストが発生し、デバッグ不能な状態に陥る。
  • ADOの癖: `Connection.BeginTrans`は明示的だ。しかし、非同期処理や外部API連携と組み合わせる際、タイムアウト後の「ゾンビ・トランザクション」がメモリを食いつぶす。

どちらを使うべきか? 単一mdb/accdb内の高速処理ならDAO一択だが、SQL Server連携や複雑なシステム間連携が絡むならADOの`Connection`オブジェクトを厳格に制御するべきだ。

—

2. 実践:鉄壁のトランザクション・テンプレート

現場で生き残るコードは、「何が起きたか」を確実に把握し、「どう戻すか」が明確である必要がある。以下は、私が長年の開発で標準化している「構造化エラーハンドリング」の雛形だ。

Public Sub ExecuteTransactionSafe()
Dim conn As Object ‘ DAO.Database または ADODB.Connection
Dim isTransStarted As Boolean

On Error GoTo ErrorHandler

‘ 初期化:DAOならDBEngine(0)(0)、ADOなら接続設定済みオブジェクト
Set conn = CurrentDb

‘ トランザクション開始
DBEngine(0).BeginTrans
isTransStarted = True

‘ 【重要】ここでビジネスロジックを実行
‘ 例: 請求データ更新、在庫減算、ログ書き込み
Call UpdateInventory(conn)
Call CreateLedgerEntry(conn)

‘ 全て成功したらコミット
DBEngine(0).CommitTrans
isTransStarted = False

Exit Sub

ErrorHandler:
‘ 【核心】ロールバックの保証
If isTransStarted Then
DBEngine(0).Rollback
‘ ここでログ出力やAPIへの通知を行う
Debug.Print “Critical Error: Transaction rolled back. Err: ” & Err.Description
End If

‘ メモリ最適化:再帰的な呼び出しを防ぐため明示的に破棄
Set conn = Nothing

‘ 異常系を呼び出し元へ伝播
Err.Raise Err.Number, “ExecuteTransactionSafe”, Err.Description
End Sub

—

3. シニアエンジニアが意識すべき「隠れた地雷」

① ゾンビ・トランザクションの排除

`isTransStarted`というフラグをわざわざ設ける理由は、`Rollback`が多重に呼ばれることによる「実行時エラー:トランザクションが開始されていません」という二次災害を防ぐためだ。エラーハンドラ内でエラーが起きると、Accessのプロセスは不安定になる。このフラグは安全装置である。

② メモリの明示的解放(Disposeの精神)

VBAはガベージコレクションを信用するな。特にADOの`Recordset`や`Connection`は、スコープを抜けた後もメモリに残留し、ファイルロックを発生させることがある。`Set obj = Nothing`は「おまじない」ではなく、メモリ解放の指令として必ず書け。

③ Windows APIとの混在における罠

トランザクション中に`Declare Function`で外部DLL(例えばExcelへの出力や、通信制御)を呼び出す場合、注意が必要だ。APIの戻り値を待っている間にタイムアウトが発生し、トランザクションが孤立することがある。
この場合、「トランザクション内ではDB操作のみを完結させ、API通信はコミット後の別スレッド(または別タイミング)で行う」のがアーキテクチャの定石だ。

—

4. 最後に:アーキテクトとしての矜持

VBAは、コードを書いた人間の「論理的純度」がそのままシステムの安定性に直結する。

「エラーが起きたら止まる」のは当たり前だ。
「エラーが起きたときに、いかにしてシステムを正常な初期状態に巻き戻し、かつその障害を運用者に正確に伝えるか」。
この一点にこそ、エンジニアの価値がある。

今日紹介したコードは、言わば「攻めの防衛」だ。トランザクションの整合性を担保することで、初めて我々は、安心して複雑なビジネスロジックの実装に専念できる。

さあ、コードを書き換えろ。あなたのシステムに、真の堅牢性を。

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