Access VBAの深淵:DAOとADO、トランザクションの「排他」が握る運命
長年、レガシーとモダンが交差する現場を渡り歩いてきたが、未だに「DAOとADO、どちらを使えばいいのか?」という初歩的な問いに、表層的な回答で済ませているエンジニアが多い。
これは単なるAPIの選択ではない。メモリの呼吸、Lockの深さ、そしてトランザクションがOSのカーネルレベルでどう排他制御に食い込んでいるかという「アーキテクチャの生存戦略」の問題だ。今日は、DAOとADOがマルチユーザー環境でどう牙を剥くのか、その核心にメスを入れる。
1. DAOとADO:その「排他」の系譜
DAO(Data Access Objects)は、Accessエンジンのネイティブな身体だ。`BeginTrans`を叩いた瞬間、JET/ACEエンジンはページレベルでのロックを保持し、ローカル環境では極めて高速に動く。しかし、それは「Accessの世界」に閉じ込められた特権に過ぎない。
一方、ADO(ActiveX Data Objects)はOLE DBという汎用的なインターフェースを介す。「外の世界」と繋がるための汎用性がある反面、トランザクションを開始すると、接続先となるサーバーやドライバーの挙動に依存する。
ここで重要なのは、「DAOは排他制御をAccessエンジンに丸投げするが、ADOは接続先(プロバイダ)のロックポリシーを継承する」という点だ。
2. トランザクション:デッドロックという名の罠
マルチユーザー環境で最も恐ろしいのは、トランザクションが保持するロックの「昇格」だ。
- DAOの挙動: `BeginTrans`中にレコードを更新すると、そのページ全体がロックされる。別ユーザーが同じページに触れようとすると、JETエンジンが待ち行列を作る。
- ADOの挙動: サーバー側のカーソル(Server-side Cursor)を利用している場合、接続が切れるまでロックが解放されないケースがある。これが、ネットワークの瞬断と重なった時、システムは静かにデッドロックの渦に飲み込まれる。
現場で使えるデッドロック回避の極限策
デッドロックを回避する鉄則は「トランザクションを極限まで短くする」ことだ。しかし、多くのエンジニアは「計算処理」までトランザクションの中に入れてしまう。
‘ 【推奨パターン】トランザクションは「書き込み」の直前のみ
Public Sub SafeUpdateTransaction()
Dim ws As DAO.Workspace
Dim db As DAO.Database
Set ws = DBEngine.Workspaces(0)
Set db = CurrentDb
‘ 1. 重い計算や外部API呼び出しはトランザクションの外で行う
Dim processedData As String
processedData = ExpensiveCalculation()
‘ 2. トランザクションは更新の最小単位に限定
ws.BeginTrans
On Error GoTo RollbackHandler
db.Execute “UPDATE T_Inventory SET Stock = Stock – 1 WHERE ID = 1”, dbFailOnError
ws.CommitTrans
‘ 3. オブジェクトの明示的解放(メモリリークを防ぐ)
Set db = Nothing
Set ws = Nothing
Exit Sub
RollbackHandler:
ws.Rollback
MsgBox “更新失敗: ロールバックしました”, vbCritical
Set db = Nothing
Set ws = Nothing
End Sub
3. レガシー保守のための「メモリ解放」の真実
Access VBAにおいて、`Set obj = Nothing`を怠ることは罪である。特に`Recordset`を多用するシステムでは、これがメモリリークを招き、ガベージコレクションが働かないAccessにおいて、アプリケーションのクラッシュを誘発する。
さらに一歩踏み込むなら、Windows APIを使い、現在のプロセスが使用しているメモリを監視すべきだ。`GlobalMemoryStatusEx`などのAPIを呼び出し、特定の閾値を超えたら強制的にオブジェクトを掃討するロジックを組み込むのが、伝説的なアーキテクトの矜持である。
4. なぜ今、DAOとADOを使い分けるべきか
私の結論はこうだ。
1. Access内部テーブルが主役ならDAOを使い倒せ: `dbOpenDynaset`のパフォーマンスは依然として最強だ。複雑な排他制御が必要ない社内ツールなら、DAOの挙動を信じろ。
2. SQL Serverや外部DBが絡むならADO一択: `ADODB.Connection`の`CommandTimeout`を適切に設定し、`CursorLocation = adUseClient`を活用して、サーバー側のロック負荷を軽減させる。これが大規模システムを支える唯一の道だ。
最後に:エンジニアへの提言
技術は「動く」だけでは不十分だ。その裏側で何が起きているか、トランザクションがどのタイミングでカーネルに割り込みをかけているか、その気配を感じ取れるようになって初めて、君たちは「システムを掌握した」と言える。
Accessはレガシーではない。使い手の技量次第で、いまだに最前線で戦える強力な兵器だ。コードに魂を込めろ。次にリファクタリングをするのは、他でもない君自身なのだから。
