【入門編】ADO接続のタイムアウト制御:ネットワーク不安定時のフリーズを回避する接続設定術 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

「応答なし」の悪夢を断ち切る —— ADO接続におけるタイムアウト制御の極意

こんにちは。今日は、Access VBAを使って「外部のデータベース(SQL Serverなど)と連携する」という、一歩踏み込んだプロフェッショナルな領域についてお話ししましょう。

あなたが一生懸命書いたコードが、ネットワークの瞬断やサーバーの負荷によって「応答なし(フリーズ)」の状態に陥り、Accessが真っ白になって動かなくなる……。そんな経験はありませんか?

「マクロの記録」から卒業し、自力でコードを書くようになった皆さんが必ずぶつかる、非常に重要な壁。それが「タイムアウト制御」です。

ここをマスターすれば、あなたの作るシステムは「ただ動くもの」から「現場で信頼されるプロの道具」へと進化します。さあ、一緒にその仕組みを解き明かしていきましょう。

1. なぜAccessは「フリーズ」してしまうのか?

まず、敵の正体を知ることから始めましょう。

通常、Access内部のテーブル(ローカルテーブル)を操作しているときは、フリーズすることは滅多にありません。しかし、SQL Serverなどの外部データベースにADO(ActiveX Data Objects)を使って接続した瞬間、ゲームのルールが変わります。

データを取りに行くとき、あなたのプログラムは「ネットワーク」という目に見えない細い糸を通って、遠くのサーバーへ手を伸ばします。

もし、その糸が途中で切れていたり、サーバーが返事をしなかったりしたらどうなるでしょうか?
プログラムは「返事が来るまで、ずっと待ち続ける」という性質を持っています。この「待ち」が、Accessの画面を固まらせ、ユーザーに「応答なし」という恐怖を与えてしまうのです。

2. 二つの「待ち時間」を使い分ける

プロのエンジニアは、この「待ち」を2つの異なるフェーズで制御します。ここが最も重要なポイントです。

① ConnectionTimeout(接続のタイムアウト)

これは、「サーバーの玄関にたどり着けるか?」という時間です。
「サーバーを探して、接続を確立する」までの制限時間です。もしネットワークが不安定で玄関が開かなければ、ここで「諦める」という判断を下します。

② CommandTimeout(コマンドのタイムアウト)

これは、「注文した料理がいつ出てくるか?」という時間です。
接続はできたけれど、いざ「大量のデータを送って!」と命令(SQLを実行)したとき、サーバーが処理に時間がかかりすぎている場合に、「これ以上待てないから一旦中止する」という判断を下すための時間です。

項目 対象フェーズ 役割
ConnectionTimeout 接続時 サーバーへの「挨拶」が成功するまでの待ち時間
CommandTimeout 実行時 SQL命令に対して「結果」が返ってくるまでの待ち時間

初心者が陥りやすい罠:
「接続が遅いから」といって、両方を極端に長く設定したり、逆に両方を短くしすぎたりすると、システムは非常に不安定になります。このバランスが、設計の腕の見せ所です。

3. 実践:フリーズを回避する「黄金のコードパターン」

それでは、実際にどのようにコードを書けばよいのか。現場でそのまま使える、堅牢な接続ルーチンを見てみましょう。

Option Compare Database
Option Explicit

' ---------------------------------------------------------------------------
' 関数名:GetExternalData
' 概要  :SQL Serverからデータを取得する(タイムアウト制御付き)
' ---------------------------------------------------------------------------
Public Sub GetExternalData()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim strConn As String
    Dim strSQL As String
    
    ' --- 設定値(ここは環境に合わせて調整してください) ---
    ' 接続文字列(例:SQL Serverへの接続情報)
    strConn = "Provider=SQLOLEDB;Data Source=YourServerName;Initial Catalog=YourDBName;Integrated Security=SSPI;"
    ' 実行するSQL
    strSQL = "SELECT * FROM LargeTable" 
    ' ----------------------------------------------------

    ' オブジェクトの生成
    Set cn = New ADODB.Connection
    Set rs = New ADODB.Recordset

    On Error GoTo ErrorHandler ' エラーハンドリングの開始

    ' 【重要】1. 接続のタイムアウト設定 (ConnectionTimeout)
    ' サーバーに繋がるまで「15秒」待つ。これを超えたらエラーへ飛ばす。
    cn.ConnectionTimeout = 15

    ' 接続開始
    Debug.Print "接続を試行中..."
    cn.Open strConn
    Debug.Print "接続成功!"

    ' 【重要】2. コマンドのタイムアウト設定 (CommandTimeout)
    ' SQLを実行してから結果が返るまで「60秒」待つ。
    ' 重い集計処理がある場合は、ここを長めに設定する。
    cn.CommandTimeout = 60

    ' SQLの実行
    Debug.Print "データを取得中..."
    rs.Open strSQL, cn, adOpenStatic, adLockReadOnly

    ' 結果の表示(テスト用)
    If Not rs.EOF Then
        MsgBox "データの取得に成功しました!", vbInformation
    Else
        MsgBox "データは空でした。", vbExclamation
    End If

CleanUp:
    ' --- 後処理(オブジェクトのライフサイクルを管理する) ---
    ' 開いているものは必ず閉じる。これがメモリリークを防ぐ鉄則です。
    On Error Resume Next
    If Not rs Is Nothing Then
        If rs.State = adStateOpen Then rs.Close
    End If
    If Not cn Is Nothing Then
        If cn.State = adStateOpen Then cn.Close
    End If
    Set rs = Nothing
    Set cn = Nothing
    Debug.Print "後処理完了。"
    Exit Sub

ErrorHandler:
    ' --- エラーキャッチ(ここが「応答なし」を防ぐ防波堤) ---
    Select Case Err.Number
        Case -2147467259 ' ADODBのタイムアウトエラー(代表的な番号)
            MsgBox "【タイムアウトエラー】" & vbCrLf & _
                   "サーバーからの応答がありませんでした。ネットワークを確認してください。", vbCritical
        Case Else
            MsgBox "【予期せぬエラー】" & vbCrLf & _
                   "エラー番号: " & Err.Number & vbCrLf & _
                   "内容: " & Err.Description, vbCritical
    End Select
    Resume CleanUp
End Sub

4. プロの視点:なぜこの書き方が「強い」のか

このコードには、単に動くだけではない、3つの「設計思想」が込められています。

① `On Error GoTo ErrorHandler` による「脱出経路」の確保

タイムアウトが発生したとき、プログラムが「停止」してはいけません。エラーをキャッチして、「通信環境を確認してください」というユーザーに優しいメッセージを出して、安全に終了する。これが、フリーズを防ぐ最大の鍵です。

② `CleanUp` ラベルによる「確実な後処理」

`Set cn = Nothing` や `cn.Close` を忘れると、接続がサーバー側に残り続け、いずれサーバーの接続上限に達してシステム全体がダウンします。エラーが起きても起きなくても、必ず `CleanUp` を通って後片付けをする。これが、オブジェクトのライフサイクルを掌握するエンジニアの作法です。

③ 適切な秒数の設定

`CommandTimeout = 0` と設定すると、実は「タイムアウトなし(無限に待つ)」という意味になります。これは「フリーズを許可する」と言っているのと同じです。絶対に避けてください。業務の特性に合わせて、「5分待ってもダメなら諦める」といった現実的な数字を入れましょう。

まとめ:ここをクリアすれば、Access VBAの基本はバッチリですよ

タイムアウト制御は、一見すると地味な作業です。しかし、この「もしもの時」を想定したコードを書けるかどうかが、アマチュアとプロを分ける決定的な境界線になります。

1. `ConnectionTimeout` で接続の失敗を制御する。
2. `CommandTimeout` で処理の停滞を制御する。
3. `ErrorHandler` で、エラーを「フリーズ」ではなく「メッセージ」に変える。

この3点を意識するだけで、あなたの作るAccessアプリケーションの信頼性は劇的に向上します。

一歩ずつ、着実に。コードの背後にある「動き」を想像しながら、素晴らしいプログラムを書き上げてください。応援していますよ!

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