Access VBAを掌握する極限の知見:接続プーリングを意識したADOコネクション再利用戦略
こんにちは。大規模なAccess業務システムの裏側、そして数々のカオスなスパゲッティコードと戦ってきたチーフアーキテクトの私だ。
現場でよく見かける光景がある。
「データを1件更新するたびに `CurrentProject.Connection.Open` を叩き、終わったら `Close` する」
……おっと、ここで冷や汗をかいた開発者は、今日の記事でその悪癖を完全に断ち切ってほしい。
Access VBA、そして背後にあるADO(ActiveX Data Objects)の挙動を深く理解していないと、無駄な接続・切断のオーバーヘッドによってアプリケーションは重くなり、最悪の場合はリソースリークやパフォーマンス低下を引き起こす。
今回は、プロの現場で通用する「接続プーリングを意識したADOコネクションの再利用戦略」をロジカルかつシャープに伝授しよう。
—
なぜ毎回の `Open` / `Close` は「罪」なのか?
データベースとの接続(Connection)の確立は、OSレベルで見ても、COMコンポーネントの初期化という観点で見ても、非常に「重い」処理だ。
特に外部のSQL Serverや、ローカルであってもJet/ACEエンジンを叩く際、毎回コネクションを生成・破棄することは、例えるなら「コンビニに買物に行くたびに新車を購入し、帰ってきたら廃車にする」ようなものである。
AccessにおけるADOとDAOの立ち位置
AccessのデフォルトはDAO(Data Access Objects)だが、外部DB(SQL ServerやOracle、PostgreSQLなど)との連携や、高度な非接続型レコードセットの操作にはADOが不可欠だ。
しかし、ADOを使う際に最もやってはいけないのが、プロシージャのたびに独自のConnectionオブジェクトを生成・破棄するアンチパターンである。
—
決定版:シングルトン・コネクション管理クラスの実装
「じゃあ、グローバル変数にコネクションを入れっぱなしにすればいいのか?」
短絡的なグローバル変数の乱用は、意図せぬタイミングでの接続断や状態の汚染(ダーティリードやトランザクションの残留)を生む温床となる。
プロが取るべきアプローチは、「カプセル化されたシングルトン・パターンによるコネクション管理モジュール」の作成だ。
以下のコードを、新規クラスモジュールとして作成し、名前を `clsDBManager` とせよ。
クラスモジュール:`clsDBManager`
Option Explicit
‘ プライベートなコネクションインスタンス(モジュールレベルで永続化)
Private m_Cnn As ADODB.Connection
‘ 接続文字列(必要に応じてSQL ServerやローカルACEに変更)
Private Const CONNECTION_STRING As String = _
“Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Data\MasterDB.accdb;Persist Security Info=False;”
‘ クラス初期化時にコネクションは即座に開かず、遅延初期化(Lazy Initialization)を採用する
Private Sub Class_Terminate()
Call Disconnect
End Sub
‘ 堅牢なコネクション取得プロパティ
Public Property Get Connection() As ADODB.Connection
If m_Cnn Is Nothing Then
Set m_Cnn = New ADODB.Connection
m_Cnn.ConnectionString = CONNECTION_STRING
m_Cnn.CursorLocation = adUseClient ‘ クライアントサイドカーソルでパフォーマンス最適化
m_Cnn.Open
Else
‘ 接続が予期せぬ切断(タイムアウトやネットワークエラー)を起こしていないか死活監視
If m_Cnn.State = adStateClosed Then
m_Cnn.Open
End If
End If
Set Connection = m_Cnn
End Property
‘ 明示的な切断メソッド(アプリケーション終了時やリセット時にのみ呼ぶ)
Public Sub Disconnect()
On Error Resume Next
If Not m_Cnn Is Nothing Then
If m_Cnn.State = adStateOpen Then m_Cnn.Close
Set m_Cnn = Nothing
End If
On Error GoTo 0
End Sub
—
アプリケーション全体でのスマートな利用戦略
上記のクラスモジュールを用意したら、実際の業務ロジックではどのように振る舞うべきか。
ポイントは、「コネクションのライフサイクルと、トランザクションのライフサイクルを明確に分離する」ことだ。
以下の標準モジュールまたはフォームのコードを見てほしい。ここではコネクションを「閉じない」代わりに、レコードセットやコマンドの使い回しに注力している。
標準モジュール:`modBusinessLogic`
Option Explicit
‘ アプリケーション全体で唯一のDBマネージャーインスタンスを保持するラッパー
Private p_DBManager As clsDBManager
Private Function GetDB() As clsDBManager
If p_DBManager Is Nothing Then
Set p_DBManager = New clsDBManager
End If
Set GetDB = p_DBManager
End Function
‘ 業務データの安全な一括登録サンプル(トランザクション制御)
Public Sub ExecuteBatchProcess()
Dim cmd As ADODB.Command
Dim cnn As ADODB.Connection
‘ マネージャーから「生きている」コネクションを取得(新規オープンは発生しない)
Set cnn = GetDB.Connection
‘ トランザクション開始
cnn.BeginTrans
On Error GoTo ErrorHandler
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandType = adCmdText
‘ 1つ目の処理
cmd.CommandText = “UPDATE T_Stock SET Quantity = Quantity – 1 WHERE ItemID = ‘A001′”
cmd.Execute
‘ 2つ目の処理
cmd.CommandText = “INSERT INTO T_Log (LogDate, Action) VALUES (Now(), ‘Stock Decremented’)”
cmd.Execute
‘ 正常終了:コミット
cnn.CommitTrans
MsgBox “バッチ処理が正常に完了しました。”, vbInformation
GoTo CleanUp
ErrorHandler:
‘ 異常終了:ロールバックでデータ整合性を死守
If Not cnn Is Nothing Then cnn.RollbackTrans
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
CleanUp:
‘ コネクションは閉じない! コマンドオブジェクトのみ破棄
Set cmd = Nothing
Exit Sub
End Sub
‘ アプリケーション終了時に必ず呼ぶクリーンアップ関数
Public Sub ApplicationShutdown()
If Not p_DBManager Is Nothing Then
p_DBManager.Disconnect
Set p_DBManager = Nothing
End If
End Sub
—
チーフアーキテクトからの実務的アドバイス:3つの鉄則
1. 「使い捨てコネクション」の誘惑に負けるな
「バグりそうだから毎回Open/Closeする」というのは、設計逃避にすぎない。コネクションの生存期間をアプリケーションのライフサイクルに同期させることで、オーバヘッドは劇的に消滅し、キビキビ動くUIが手に入る。
2. エラーハンドリングにおけるトランザクションの巻き戻し
コネクションを共有する場合、トランザクションの途中でエラーが発生したまま放置されると、後続の処理がデッドロックや不正なロック状態に陥る。必ず `On Error GoTo` で `RollbackTrans` を通る動線を確保しろ。
3. ADOのカーソル位置(CursorLocation)の選定
Access(Jet/ACE)やローカルDBを使う場合、`adUseClient` を指定してクライアントサイドカーソルにすることで、サーバー側(プロバイダ側)のラウンドトリップを削減し、ネットワークやファイルI/Oの負荷を最小化できる。
—
結び
プロとアマチュアの差は、「動くコードを書くか」ではなく、「リソースのライフサイクルを完全に支配しているか」にある。
今回紹介した「シングルトンによるコネクション管理」を導入すれば、Access特有のモタつきとはおさらばだ。明日からの開発で、ぜひこのアーキテクチャを組み込んでみてほしい。あなたの書くコードのパフォーマンスと信頼性は、見違えるほど強固なものになるはずだ。
