SQL Anywhere 11 をはじめとして、Ultra Light データベースは、イベントおよび通知のサポートを提供します。データの修正、同期の要求およびコミットなどの特定のイベントが発生したときに、アプリケーションが通知を受け取ることができます。このチュートリアルでは、Windows データベース・コンソール・アプリケーションを使用してイベント通知の使用方法について説明します。
作成されるアプリケーションはマルチスレッド型であるため、新しい通知のチェックを行っても、アプリケーションとユーザとのやり取りが妨害されることはありません。データベースへの接続は、データベース・エンジン・クライアント・ライブラリを介して行われます。したがって uleng11.exe ユーティリティが使用されるため、さまざまなアプリケーションからデータベースに接続できます。具体的には、このチュートリアルでは管理プログラムのInteractive SQL を使用します。
アプリケーションは、“Commit” システム・イベントの通知を取得するよう登録されています。データベースの修正時には、ユーザには更新されたデータがアプリケーション内に自動的に表示されます。アプリケーション・レベルで通知をチェックするので、チェックのたびにデータベースが余計な作業を実行しないで済みます。
このチュートリアルでは、単純化するためにエラー・チェックを最小限にしました。推奨案では、開発者はすべての戻り値をチェックすべきであるとされています。サンプルは
Visual C++ で記述されていますが、イベントおよび通知の API は、サポートされるすべての言語で提供されています。プログラミング言語
(エラー処理など) の相違や関数名の相違がありますが、提供されているサンプルは、C#
や Visual Basic など他の言語でも使用できるように簡単に記述し直すことができます。
この特性の詳細については、オンライン・マニュアル内の「イベント通知の操作」を参照してください。
要件
このチュートリアルの作成には、以下が使用されています。
サンプルの実行
このチュートリアル用のすべてのファイルを格納するためのディレクトリを作成してください。このディレクトリを
C:\tutorial\cpp であると仮定してチュートリアルを進めます。別の名前でディレクトリを作成する場合、これ以降はディレクトリ名をその名前に置き換えてください。
データベースのセットアップ:
- コマンド・プロンプトを開き、C:\tutorial\cpp に移動します。
- コマンドulcreate temp.udb を使用して、Ultra Light データベースを作成します。
- Interactive SQL を使用して、データベースに接続します (dbisql -ul -c dbf=C:\tutorial\cpp\temp.udb)。
- Interative SQL で、「付録 A ‐ SQL コード」のコードをコピー・アンド・ペーストして実行します。このSQL スクリプトにより、顧客名のテーブルが作成されます。
- Interactive SQL を終了します。
アプリケーションのセットアップ:
「付録 B ‐ C++ コード」に完全なコードがリストされています。
- お好きなコード・エディタを使用して、“UltraLite Event Notifications.cpp”
ファイルを新規作成します。
- ヘッダを含め、Ultra Light ネームスペースを使用し、グローバル変数を宣言します。
#include <stdio.h>
#include "windows.h"
#include "uliface.h"
#include <stdlib.h>
using
namespace UltraLite;
static char* const conn_string = "DBF=temp.udb;UID=dba;PWD=sql";
int flag=1;//flag to signal shutdown of
watchthread. |
- データベースのデータを表示する出力関数を作成します。
void output(ResultSet
*rs) { SYSTEMTIME lt; char *dest = (char*)malloc(sizeof(char)*30);
//Just some output formatting. system("cls"); printf("
_____________________________________________ \n");
printf("| %10s | %30s
|\n","cust_id","cust_name"); printf("|____________|________________________________|\n");
while(rs->Next()) {
rs->Get(2).GetString(dest,30); printf("|
%10d | %30s |\n",(int)rs->Get(1),dest); } printf("|____________|________________________________|\n");
//Display the time for the last refresh of the
data. GetLocalTime(<); printf("Last refresh done at:
%02d:%02d:%02d\n",lt.wHour,lt.wMinute,lt.wSecond);
//Clean up. free(dest);
rs->Release(); } |
db_check() 関数は、このアプリケーションのセカンド・スレッドのエントリ・ポイントです。この関数は、データベースから新しい通知が送信されているかどうかを
(バックグラウンドで) モニタし、送信されていた場合は表示データをリフレッシュします。その間、アプリケーションの残りの部分は、ユーザの入力をチェックできます。
DWORD WINAPI db_check(LPVOID
lpParam)
{
char* ulevent = (char*)malloc(sizeof(char)*20); //init objects and open connection ULSqlca _sqlca; _sqlca.Initialize(); DatabaseManager* dbMgr =
ULInitDatabaseManager(_sqlca);
Connection* _conn =
dbMgr->OpenConnection(_sqlca,conn_string); //test the connection if(_conn !=
NULL) { //this is
it...
_conn->RegisterForEvent("Commit","ULCustomer",NULL,true); //Do a first
output.
PreparedStatement *stmt = _conn->PrepareStatement(UL_TEXT("SELECT * from ULCustomer"));
output(stmt->ExecuteQuery()); do { //Check for any
notifications on the default queue. If the table has been modified, refresh
it.
//There is only one regiestered event, so there is no need to check for any
additional paramteres.
_conn->GetNotification(NULL,100).GetString(ulevent,20); if(strcmp("Commit",ulevent)==0) { PreparedStatement *stmt =
_conn->PrepareStatement(UL_TEXT("SELECT * from
ULCustomer"));
output(stmt->ExecuteQuery()); } } while(flag); _conn->Release(); } else
{ printf("Error opening connection to database with the following
connection string: %s\n",conn_string); }
free(ulevent);
dbMgr->Shutdown(_sqlca);
_sqlca.Finalize(); return 0; } |
- アプリケーションのエントリ・ポイントとなる main 関数を作成します。
起動時に、新しい通知をモニタする新たなスレッドが作成されます。その後は、単純化するために、main 関数はアプリケーションを終了するためのユーザ入力を待ちます。
int main()
{
DWORD dwThreadID;
HANDLE watchthread =
CreateThread(NULL,0,db_check,NULL,0,&dwThreadID);
getchar();
flag=0;
switch(WaitForSingleObject(watchthread,INFINITE))
{
case WAIT_OBJECT_0:
{
printf("All threads
ended, cleaning up for application exit...\n");
break;
}
default:
{
printf("Wait error (%d)\n", GetLastError());
break;
}
}
return 0;
} |
アプリケーションのコンパイル:
- C:\tutorial\cpp フォルダに、アプリケーションをコンパイルするための“makefile” ファイルを新規作成します。「付録 C ‐ Makefile コンテンツ」のコードをコピー・アンド・ペーストします。
- Visual Studio 2008 Command Prompt を開きます。C:\tutorial\cpp に移動し、nmake.exe を実行します。実行プログラムUltraLite Event Notifications.exe が作成されます。
サンプルの実行:
- ファイル UltraLite Event Notifications.exe を実行します。アプリケーションが起動されます。アプリケーションはデータベースのレコードを出力し、ユーザの入力を待ちます。
- Interactive SQL を使用してデータベースに接続します。コマンド・プロンプトをもう 1 つ開き、dbisql -ul -c dbf=C:\tutorial\cpp\temp.udb を実行します。
- Interactive SQL で、以下の文を実行します。:
INSERT INTO
ULCustomer (cust_id, cust_name) VALUES (1, 'Test Customer');
COMMIT; |
- Visual Studio Command Prompt で、“Last refresh time” が COMMIT 文の実行後の時間に更新されていて、新しいローが表示されていることに注意してください。任意のキーをタイプしてから、[Enter] を押してアプリケーションを終了します。
- nteractive SQL とコマンド・プロンプトを終了します。これでチュートリアルは終了です。
結論
Ultra Light イベント通知を使用して、データベースのコミット時にアプリケーションによって表示されるデータをリフレッシュすることができました。この処理は、すべてバックグラウンドで自動的に実行され、ユーザとアプリケーションのやり取りが妨害されることはありません。
Ultra Light イベント通知は、開発者に以下の重要な機能を提供します。
- 変更のプーリングがアプリケーション・レベルで行われるため、データベースで実行する必要がある作業の量を削減できます。
- 提供されるシステム・イベント (Commit、SyncComplete、および TableModified) に加えて、開発者が独自のイベントを宣言し、登録してトリガできます。
通知の取得は、新しいイベントに簡単に移植できる一般的な関数を使用して実行されます。したがって、アプリケーションでは、通常であればプーリング・メカニズムの修正が必要なデータベースの変更を行う必要がありません。また、データベースについても、プーリング・メカニズムを実装するためにスキーマを変更する必要がありません。
付録 A ‐ SQL コード
create
table ULCustomer ( cust_id integer not null primary key, cust_name varchar(30) );
create unique index ULCustomerName on ULCustomer (cust_name);
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2000, 'Apple St. Builders'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2001, 'Art''s Renovations' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2002, 'Awnings R Us'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2003, 'Al''s Interior Design' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2004, 'Alpha Hardware'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2005, 'Ace Properties' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2006, 'A1 Contracting'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2007, 'Archibald Inc.' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2008, 'Acme Construction'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2009, 'ABCXYZ Inc.' );
INSERT INTO
ULCustomer (cust_id, cust_name) VALUES ( 2010, 'Buy It Co.' );
INSERT INTO ULCustomer (cust_id, cust_name) VALUES ( 2011, 'Bill''s Cages' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2012, 'Build-It Co.'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2013, 'Bass Interiors' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2014, 'Burger Franchise'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2015, 'Big City Builders' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2016, 'Bob''s Renovations'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2017, 'Basements R Us' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2018, 'BB Interior Design'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2019, 'Bond Hardware' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2020, 'Cat Properties'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2021, 'C & C Contracting' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2022, 'Classy Inc.'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2023, 'Cooper Construction' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2024, 'City Schools'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2025, 'Can Do It Co.' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2026, 'City Corrections'
);
INSERT INTO ULCustomer (cust_id, cust_name)
VALUES ( 2027, 'City Sports Arenas' );
INSERT
INTO ULCustomer (cust_id, cust_name) VALUES (
2028, 'Cantelope
Interiors' );
INSERT INTO ULCustomer
(cust_id, cust_name) VALUES ( 2029, 'Chicken Franchise'
); |
付録 B ‐ C++ コード
#include <stdio.h>
#include "windows.h"
#include "uliface.h"
#include <stdlib.h>
using
namespace UltraLite;
static char* const conn_string = "DBF=temp.udb;UID=dba;PWD=sql";
int flag=1;//flag to signal shutdown of
watchthread.
void output(ResultSet
*rs) { SYSTEMTIME lt; char *dest = (char*)malloc(sizeof(char)*30);
//Just some output formatting. system("cls"); printf("
_____________________________________________ \n");
printf("| %10s | %30s
|\n","cust_id","cust_name"); printf("|____________|________________________________|\n");
while(rs->Next()) {
rs->Get(2).GetString(dest,30); printf("|
%10d | %30s |\n",(int)rs->Get(1),dest); } printf("|____________|________________________________|\n");
//Display the time for the last refresh of the
data. GetLocalTime(<); printf("Last refresh done at:
%02d:%02d:%02d\n",lt.wHour,lt.wMinute,lt.wSecond);
//Clean up. free(dest);
rs->Release(); }
DWORD WINAPI
db_check(LPVOID lpParam)
{
char* ulevent = (char*)malloc(sizeof(char)*20); //init objects and
open connection ULSqlca _sqlca;
_sqlca.Initialize(); DatabaseManager* dbMgr =
ULInitDatabaseManager(_sqlca); Connection* _conn =
dbMgr->OpenConnection(_sqlca,conn_string); //test the connection if(_conn != NULL) { //this is it...
_conn->RegisterForEvent("Commit","ULCustomer",NULL,true); //Do a
first output. PreparedStatement *stmt =
_conn->PrepareStatement(UL_TEXT("SELECT * from
ULCustomer"));
output(stmt->ExecuteQuery()); do { //Check for any notifications on the default queue. If the table
has been modified, refresh it.
//There is only one regiestered event, so
there is no need to check for any additional paramteres.
_conn->GetNotification(NULL,100).GetString(ulevent,20);
if(strcmp("Commit",ulevent)==0)
{ PreparedStatement *stmt =
_conn->PrepareStatement(UL_TEXT("SELECT * from
ULCustomer"));
output(stmt->ExecuteQuery()); }
} while(flag);
_conn->Release(); } else { printf("Error opening connection to database with the following
connection string: %s\n",conn_string); }
free(ulevent); dbMgr->Shutdown(_sqlca);
_sqlca.Finalize(); return
0; }
int main()
{
DWORD dwThreadID;
HANDLE watchthread =
CreateThread(NULL,0,db_check,NULL,0,&dwThreadID);
getchar();
flag=0;
switch(WaitForSingleObject(watchthread,INFINITE))
{
case WAIT_OBJECT_0:
{
printf("All threads
ended, cleaning up for application exit...\n");
break;
}
default:
{
printf("Wait error (%d)\n", GetLastError());
break;
}
}
return 0;
} |
付録 C ‐ Makefile コンテンツ
IncludeFolders=/I
"$(WindowsSdkDir)\Include" /I "$(SQLANY11)\SDK\Include"
LibraryFolders=/LIBPATH:"$(SQLANY11)\UltraLite\win32\386\Lib\vs8"
/LIBPATH:"$(WindowsSdkDir)\Lib"
Libraries=ulbase.lib ulimpc.lib
CompileOptions=/c /W3 /Zi /DWIN32
/DUL_USE_DLL
"UltraLite Event
Notifications.exe" : "UltraLite Event Notifications.obj"
link /NOLOGO /DEBUG "UltraLite Event Notifications.obj"
$(LibraryFolders) $(Libraries)
"UltraLite
Event Notifications.obj" : "UltraLite Event Notifications.cpp"
cl $(CompileOptions) $(IncludeFolders) "UltraLite Event
Notifications.cpp" |
|