VB.NET SQL Server 2005でデータの変更を監視する

[English]

データベースを使用するプログラムで、特定のデータが更新された際に何か処理を行うという場合があります。

真っ先に思いつく方法としては、「ポーリング」つまり定期的にデータベースからデータを取得して変更の確認し、もしもデータの内容に変更があれば必要な処理を行うという方法です。

しかし、ポーリング間隔を短くするとトラフィックや負荷が増えてしまい、逆にポーリング間隔を長くすれば、データ変更から実際に処理が行われるまでの遅延が大きくなってしまいます。

そこで、使用できる環境が限定されてしまいますが、Microsoft SQL Server 2005 以降のデータベースを使用している場合クエリ通知を検討してみると良いかもしれません。

使い方は簡単で、

  1. 監視したいレコードを通常の SELECT文 で問い合わせる(クエリ)
  2. そのSqlCommandとイベントハンドラをSqlDependencyに登録する
  3. データに変更があった場合、登録したイベントハンドラが呼び出される(通知)
Imports System.Data.SqlClient
    Private sqlDependency As SqlDependency
     
    ''' <summary>
    ''' クエリ通知サンプル
    ''' </summary>
    Private Sub button1_Click(sender As Object, e As EventArgs)
        ' 接続文字列
        Dim connectionString As String = "Data Source=127.0.0.7;Initial Catalog=TestDatabase;Integrated Security=True;"
    
        ' クエリ通知の開始(一度だけ開始すれば良い)
        sqlDependency.Start(connectionString)
    
        Using sqlConnection As New SqlConnection(connectionString)
            Using sqlCommand As SqlCommand = sqlConnection.CreateCommand()
                sqlConnection.Open()
                sqlCommand.CommandText = "SELECT Student.Name, Student.Sex, Student. FROM dbo.Student"
    
                ' クエリ通知イベントを登録する
                Me.sqlDependency = New SqlDependency(sqlCommand)
                AddHandler Me.sqlDependency.OnChange, AddressOf OnChange
    
                ' クエリの結果が必要であれば sqlCommand.ExecuteReader() などを使用する
                sqlCommand.ExecuteNonQuery()
            End Using
        End Using
    End Sub
    
    ''' <summary>
    ''' クエリ通知イベント
    ''' </summary>
    Private Sub OnChange(sender As Object, e As EventArgs)
        System.Diagnostics.Debug.WriteLine("OnChange")
    
        ' SqlDependency からのイベントは一度しか発生しないのでイベントを削除
        RemoveHandler Me.sqlDependency.OnChange, AddressOf OnChange
    End Sub

いくつか注意点があり、

  1. クエリ通知がサポートしているのは特定コマンドのみ(クエリ通知を使用するときの特別な注意事項
  2. WHERE句で抽出されなかったレコードの変更は通知されませんが、SELECTしたカラム以外が変更された場合は通知される(つまり、Name, Sex, Grade 以外に Age などがテーブルに存在する場合、それも監視対象になる)
  3. テーブル名はスキーマ名から指定する(既定のスキーマ名はdboなのでサンプルではdbo.Student)

など、少し使い勝手に難はありますが、使いこなすことが出来るとかなり便利な機能です。

詳しくはMSDNのSQL Server のクエリ通知 (ADO.NET)を確認して下さい。

使用環境: Visual Studio 2010, .NET Framework 4, Microsoft SQL Server 2008