*

[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

関連記事

logo

[Unity, C#]曲線を描こう エルミート曲線とベジエ曲線

演出を作る際に綺麗な曲線を描きたいですよね。 というわけでC#でエルミート曲線とベジエ曲線を計算す

記事を読む

Unity_

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

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

記事を読む

logo

[Unity]Unity2Dチュートリアル 同じ色のパズルを消去する ソース解説

◆全文 using UnityEngine; using System.Collecti

記事を読む

logo

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

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

記事を読む

Unity_

[Unity]Unity2Dチュートリアル 番外編 これパズドラじゃなくね?

前回の続き。 パズドラみたく直線で3つ以上連なっているときに消したいんです。 そして、何を勘

記事を読む

Unity_

[Unity]Unity 2Dチュートリアル スプライトをクリック(タップ)して削除する

前回、スプライトを置くことが出来たのですが、動かせるようにしたいところです。 ドラッグして動

記事を読む

Unity2_1

[Unity]Unity2Dチュートリアル スプライトを利用する

前回の続き。 早速、スプライトを設置して作っていきましょう。 ※スプライトとは スプライ

記事を読む

addcomp

[Unity]コードリファレンス コンポーネントをアタッチする。

コンポーネントをプログラム実行時に追加します。 AddComponent() AddComp

記事を読む

logo

[C#]パスワード暗号化プログラムの初歩

パスワード暗号化の初歩的方法。 子供だましみたいなプログラムですね。 これは入社四か月の頃にプロ

記事を読む

visualstudio_

[visual studio]ODBC等のConnection Stringの簡単な作り方

Connection Stringって大体いつも検索して、それを使ってみて、だめだったりOKだったり

記事を読む

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 ↑