|
データベース【TIBTableでサーバーDBにアクセス】 |
前回はTIBTableを使って簡単なDBを作ってみましたがスタンドアロン型での方法でした。今回は同じくTIBTableを使って、サーバーPCに置いたデータベースにアクセスする事を考えてみます。
TIBTableでは、TDataSourceを使って TDBGrid に表示させる事が出来るというのは前回に書きましたが、同様に、TDBNavigator や TDBEdit 等も利用する事が出来ます。
まずは、プロジェクト「d002」の準備を行います。「C:\DelphiProgram\jww」フォルダの中に「d002」というフォルダを作成し、前回の「d001」からファイルをがさっとコピーしてきます。その方が楽ですので。Delphi6を起動します。メニュー「プロジェクト」→「オプション」を実行し、下記の設定を行います。
[アプリケーション]頁
タイトル | d002−データベース作成 |
[ディレクトリ/条件]頁
パス及びディレクトリ | C:\DelphiProgram\db\d002 |
メニュー「ファイル」→「プロジェクトに名前を付けて保存」
「C:\DelphiProgram\db\d002」の中に「d002.dpr」として保存
メニュー「表示」→「プロジェクトマネージャ」
を実行し、コード画面の左側にドッキングさせておきます。
下記のように画面レイアウトを変更しました。
「DBNavigator1」「DBEdit1」「DBEdit2」のプロパティ指定
d001ではボタンを押してデータベースを作成していましたが、こちらでは、起動時=フォーム表示の際にデータベースやテーブルを作成するようにしています。
スタンドアロンの場合には、データベースはアプリケーションフォルダ等に入れたり等は出来ましたが、クライアント/サーバー(C/S)の場合には、データを格納するフォルダというのは「ここ!」という具合に固定化して、各クライアントからも指示しやすいフォルダにするのが良いでしょう。ちなみにそのフォルダを共有設定する必要はありません。逆に、変にいじられないようにするため共有設定はしない方が無難でしょう。
サーバーの指示は、IPアドレスで指定し(私の場合は「192.168.1.10」という番号を振っていますが便宜に応じて指定して下さい)、サーバーのフォルダを指定します。各クライアントPCで設定する場合も、あくまでもサーバーのフォルダの指定となります。共有名やネットワークドライブ等ではありません。
// 起動時
procedure TForm1.FormShow(Sender: TObject);
begin
AppPath := ExtractFilePath(Application.ExeName);
Label1.Caption := '';
Label2.Caption := '';
// 起動時にデータベースを作成します
// データベース作成
IBDataBase1.DatabaseName := Edit1.Text + Edit2.Text + 'TEST.FDB' ;
IBDatabase1.Params.Clear ;
IBDatabase1.Params.Add('USER "SYSDBA"');
IBDatabase1.Params.Add('PASSWORD "masterkey"');
IBDatabase1.Params.Add('PAGE_SIZE 4096');
try
IBDataBase1.CreateDatabase;
except
// 既に作成済み
end;
// データベース接続
IBDataBase1.DatabaseName := Edit1.Text + Edit2.Text + 'TEST.FDB' ;
IBDataBase1.Connected := False ;
IBDatabase1.Params.Clear ;
IBDatabase1.Params.Add('USER_NAME=SYSDBA');
IBDatabase1.Params.Add('PASSWORD=masterkey');
IBDatabase1.Connected := True ;
IBTransaction1.Active := True ;
// テーブル作成
try
with IBTable1 do begin
TableName := 'TEST' ;
if not(IBTable1.Exists) then begin
StoreDefs := True ;
// テーブルの項目
with FieldDefs do begin
Clear;
with AddFieldDef do begin
Name := 'N';
DataType := ftInteger ;
Required :=True;
end;
with AddFieldDef do begin
Name := 'MOJIDATA';
DataType := ftString ;
Size := 20 ;
end;
end;
// インデックス
with IndexDefs do begin
Clear;
with AddIndexDef do begin
Name := 'INDEX1';
Fields := 'N';
end;
end;
//
CreateTable;
end;
end;
except
;
end;
IBTable1.StoreDefs := False ;
IBDatabase1.Connected := False ;
end; |
以上、DatabaseNameの指定が異なるだけで他は前回と同じです。DatabaseNameの指定は、
(サーバーのIPアドレス)+「:」+(サーバーのデータフォルダ)+(データベースファイル名)
となります。一旦接続を切っています。[DB接続]ボタンを押してデータベースに接続し、データを開きます。[DB切断]ボタンを押すとデータベースとの接続を終了します。データは閉じられます。終了時にも一応切断するようにします。
// 終了時
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// 切断作業
Button2Click(Sender);
end;
// DB接続
procedure TForm1.Button1Click(Sender: TObject);
begin
if (IBTable1.Active) then
IBDatabase1.ApplyUpdates([IBTable1]);
IBDatabase1.Connected := True ;
IBTransaction1.Active := True ;
IBTable1.Active := True ;
Label1.Caption := IBTable1.Fields[0].FieldName ;
Label2.Caption := IBTable1.Fields[1].FieldName ;
DBEdit1.DataField := IBTable1.Fields[0].FieldName ;
DBEdit2.DataField := IBTable1.Fields[1].FieldName ;
end;
// DB切断
procedure TForm1.Button2Click(Sender: TObject);
begin
if (IBTable1.Active) then
IBDatabase1.ApplyUpdates([IBTable1]);
IBTable1.Active := False ;
IBTransaction1.Active := False ;
IBDatabase1.Connected := False ;
end; |
DB接続をした際に、データフィールド(データ項目名)を割り当てて、その内容を表示出来るようにしています。
データを登録したり編集すると、キャッシュの中に入ります。その状態ではまだデータベース内のテーブルデータには入りません。ある一定量のデータがキャッシュに入るか、或いは、キャッシュデータを適用する事によって、テーブルデータが更新されます。前者の場合は状況等に依るためアテに出来ませんし、他のPCからアクセスされる事を考えても、常にデータ内容が更新されていないと問題にもなるでしょうから、データを登録した後、データを削除した後には、キャッシュデータを適用するようにします。IBTable1のイベントを定義します。
procedure TForm1.IBTable1AfterPost(DataSet: TDataSet);
begin
IBDatabase1.ApplyUpdates([IBTable1]);
end;
procedure TForm1.IBTable1AfterDelete(DataSet: TDataSet);
begin
IBDatabase1.ApplyUpdates([IBTable1]);
end; |
さて、現在表示されている DBGridのデータ一覧表は、何もしていない場合は、何もどうもなりません。他のPCからデータ書き込みがあっても、このPCで表示されている内容が自動的に勝手に変わる訳ではありません。「更新」をすることによって、一覧の内容が変わります。しかし残念ながら、TDBNavigatorの「更新」ボタンを押してもそれだけでは更新してくれません。ちゃんと更新してくれるようイベントを定義します。
procedure TForm1.IBTable1BeforeRefresh(DataSet: TDataSet);
begin
// 更新前に一旦閉じて再度開く
IBTable1.Active := False ;
IBTransaction1.Active := False ;
IBTransaction1.Active := True ;
IBTable1.Active := True ;
end; |
[更新]ボタンを押し、Refreshが行われる直前に、一旦テーブルを閉じて、トランザクションを閉じ、再度、トランザクションを開けて、テーブルを開ける、という作業をします。そうする事によって、現在の最新のデータ内容を開ける事が出来るようになります。
このトランザクションというのが、C/S型データベースを扱う際のポイントになってきます。
クライアントとサーバーのやり取りは1対1という訳ではなく、複数対1となります。そのためサーバーはデータの行き来の交通整理をする必要が出てきます。それがつまりトランザクションです。クライアントはサーバー内のデータに直接アクセスするのではなくトランザクションに対してアクセスを行います。トランザクションが受け付け窓口になってくれる訳です。もし直接アクセスするとなると、複数のPCから同時アクセスされると、無視されたりしてデータの読み書きが出来ない状況になり、それがいつまで経ってもアクセス出来ないかもしれません。それでは全く意味がありませんので、このトランザクションがうまく捌いてくれるような仕組みになっている訳です。
勿論、プログラム側で、他からのアクセスがあってこちらかのアクセスが出来ない状況であれば、キャンセルしたり、リトライしたり、という事も出来ますが、それについては以降の節で述べます。
Paradox(BDE)での TTable とは若干異なる点もありますが、TIBTable は多少の追記程度で、TTable と同じように記述する事が出来ます。つまり比較的容易に、Firebird/Interbase でC/S型データベースを作る事は出来ます。
TTableでは、TDBNavigator を使用せず、自分でレコード移動やデータ登録・編集・削除等をプログラミングする事が出来ますが、TIBTableでも同様に行う事が出来ます。それについては、また次回。
|
|
バッチファイル
BASIC
C言語のお勉強
拡張子な話
DOSプログラム
Delphi
シェアウェア
Script!World
データベース
A B C D
E F G H
I J K L
M N O P
Q R S T
U V W X
Y Z
|