*

[C#]マルチスレッドとイベントハンドラでデータベースのテーブルの値の変更を検知する。

公開日: : 最終更新日:2015/01/19 C#

システム利用中にデータベースの内容が更新

こういったシステムは往々にしてあるかと思います。
特に照会などを行うシステムでは有り得ますね。

さて、そこで、照会をしていて、テーブルの内容が更新された瞬間に照会画面に更新内容を表示したい、という場合があります。
そういう場合は、データを監視する必要があるわけですが、しかし、何秒か一度にチェックをさせるとGUIが一瞬フリーズしてしまったり等で格好良くありません。

具体的にはこんなフローになると思います。

  • 監視する
  • 監視を検知したら知らせる
  • 検知報告に従い処理する

というわけでこれを実現する簡単なForm Applicationを作ってみます。

イメージ

Delgate Multi Thread
ボタンだけ配置して、ボタンをダブルクリックしてクリックイベントに記述していきます。

ソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Data.Odbc;
using System.Windows.Forms;

namespace MultiThreadTest {
	public partial class Form1 : Form {
		public Form1() {
			InitializeComponent();
		}

		private void button1_Click(object sender, EventArgs e) {
			Observer observer = new Observer();
			ChangedEventHandler eventHandler = new ChangedEventHandler(ChangedNumberOfRecord);
			observer.Changed += eventHandler;
			observer.Start();
		}
		
		public void ChangedNumberOfRecord(object sender) {
			MessageBox.Show(sender.ToString() + "レコードの数が変更されました。");
		}
	}



	public delegate void ChangedEventHandler(object sender);

	public class Observer {
		public event ChangedEventHandler Changed;

		public int RecordNum {
			get {
				return recordNum;
			}
			set {
				this.recordNum = value;
				OnChange(this);
			}
		}
		private int recordNum;
		private void OnChange(object sender) {
			if (Changed != null) {
				Changed(sender);
			}
		}

		public Observer() {
			RecordNum = GetRecordNumber();
		}

		public void Start() {
			Thread th = new Thread(new ThreadStart(Observe));
			th.Start();
		}

		public void Observe() {
			while (true) {
				System.Threading.Thread.Sleep(1000);
				int newRecordNum = GetRecordNumber();
				if (RecordNum != newRecordNum) {
					RecordNum = newRecordNum;
				}
			}
		}

		private int GetRecordNumber() {
			int recordNum = 0;

			string[] conStrs = {
								   "Driver={iSeries Access ODBC Driver};", 
								   "System=192.168.0.999;",
								   "Uid=HOGE;",
								   "Pwd=HOGE;",
							   };

			string connectionString = string.Join("", conStrs);

			string sql =
				@"select count(*) from HOGELIB.HOGETBL";

			using (OdbcConnection con = new OdbcConnection(connectionString)) {
				con.Open();
				using (OdbcCommand cmd = new OdbcCommand(sql, con))
				using (OdbcDataReader reader = cmd.ExecuteReader()) {
					if (reader.Read()) {
						recordNum = (int)reader[0];
					}
				}
				con.Close();
			}

			return recordNum;
		}
	}
}

解説

AS400に繋いで、HOGELIBのHOGETBLのレコード数をカウントしています。
もしもレコード数が変わったらメッセージボックスが出てくるなんてことない処理。
なんてことない処理なんですが、記述が多くなって面倒です。

private void button1_Click(object sender, EventArgs e) {
    Observer observer = new Observer();
    ChangedEventHandler eventHandler = new ChangedEventHandler(ChangedNumberOfRecord);
    observer.Changed += eventHandler;
    observer.Start();
}

ChangedNumberOfRecordというメソッドをObserverのインスタンスに登録しています。
ChangedNumberOfRecordはメッセージボックスを表示するだけのメソッドなので、イベントが起きた場合にはメッセージボックスが表示されます。

public event ChangedEventHandler Changed;

イベントの宣言です。イベントはこんな感じで実装します。

public int RecordNum {
   get {
       return recordNum;
   }
   set {
        this.recordNum = value;
        OnChange(this);
   }
}

プロパティの値が変わったときにOnChangeメソッドを実行しています。後述のためです。
引数はObjectを持っていっていますね。

private void OnChange(object sender) {
    if (Changed != null) {
        Changed(sender);
    }
}

eventプロパティが設定されていたら、イベントを実行します。
前述のOnChange(this)の部分ですね。

public void Start() {
    Thread th = new Thread(new ThreadStart(Observe));
    th.Start();
}

public void Observe() {
    while (true) {
        System.Threading.Thread.Sleep(1000);
        int newRecordNum = GetRecordNumber();
        if (RecordNum != newRecordNum) {
             RecordNum = newRecordNum;
        }
    }
}

マルチスレッド部分です。
Observeというメソッドをマルチスレッドとして実行しています。
なお、これだと止める術がないので、ご注意ください。
ContinueFlgかなにかをフィールドで持たせて、外側からFalseにしてあげてwhileの条件にしてみたりなんかがいいでしょうか。

実行イメージ

Multi Thread
ボタンをクリックして、HOGELIBのHOGETBLにDFUでレコードを挿入した瞬間のイメージです。
マルチスレッドのイベントによって、登録したメソッドが実行されているのがわかります。

なお、停止する術がありませんので、暇なときに実装してみます。

ad

関連記事

Wannabenote

[Unity]Unity2Dチュートリアル 繰り返しパズルを消す その2

Unityまとめページはこちら。 前回の続き。 準備が出来たので、ソースを変更致しましょ

記事を読む

logo

[C#, Generic]UnityのAddComponentとかなんとかComponentを実装してみる

UnityのAddComponentってありますよね。 みたいなやつ。 このジェネリクスの

記事を読む

logo

[C#]BinaryFormatterなどSerializerいろいろ書いておく

github始めました -> わなびのgithub それは置いておいて、BinaryForma

記事を読む

unity pazzle

[Unity]Unity2D 番外編 消してちょっと待つ(コルーチン利用)

>タイルを再生成するときに消えたというのがわかるように、時間をおいて生成させることは可能ですか?

記事を読む

Unity_

[Unity]Unity2Dチュートリアル 画面上のGameObjectを取得する

前回の続きです。 というわけで移動の仕方は完璧です。本当なら一瞬で移動ではなく、パズドラみたく

記事を読む

logo

[C#]システム関連付けのソフトでファイルを起動する

事の発端 PDFをAdobeReaderで開きたいといわれました。 コマンドラインでAdobeR

記事を読む

Unity_

[Unity]Unity2Dチュートリアル 直線で3つ同色のパズルを消去する

前回の続き。 パズドラじゃなくて、パズドラ+ぷよぷよの謎パズルを作ってしまったので、 今回は

記事を読む

Unity_

[Unity]Unity2Dでパズドラのようにタイルを動かす

今回からスクリプトがかなり難しくなってくるかも。 前回の続き。 というわけで前回はドラッグで

記事を読む

logo

[C#]AS400をDBに見立ててPCのPGMからODBC接続する

◆前提条件◆ PCにClient Accessがインストールされている。 PCに.NET Fra

記事を読む

socket p2p unity

[Unity]Socket通信でP2Pすっぞ ホストへ接続

前回はホストが待ちうけするところまで作りました。 今回はクライアントがホストへ接続できるように

記事を読む

ad

Message

メールアドレスが公開されることはありません。

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

ad

  •  Auther;わなび

     「オープン系得意だよね? 俺のPCの調子悪いんだけど」という無茶振りから解き放たれゲームエンジニアに。
    C#とかUnityを扱います。
    Twitterフォロー大歓迎です。
    githubアカウント→wannabenote
  • follow us in feedly
PAGE TOP ↑