MS SQL Server Multiuser Kullanımda Veritabanı Güncelleme Gönderen: dynamo Tarih: 28 May 2007 09:44:24
Interbase/firebird te ağ ortamında diğer kullanıcıların yaptığı değişikliklerde, veritabanındaki güncellemenin diğer kullanıcılara anında yansımasıiçin
IBEvent komponenti kullanılır.MS Sql Server'de doğrudan böyle bir komponent yok. Fakat
INDY komponentlerini bu amaçla kullanabiliriz.
veritabanı güncelleme iki yöntemle yapılabilir.
1-)
indytcpclient_indytcpserver kullanarak :

public
{ Public declarations }
server,sapassword:string;
procedure BroadcastMessage;
end;
bir transaction(insert/update/delete) durumunda indytcpclient yerel ağ sistemine mesajı gönderecek bu mesajı alan indytcpserver tabloyu güncelleyecek.
IdTCPClient1-->Connected olayında göndereceğimiz mesaj var:
procedure TForm1.IdTCPClient1Connected(Sender: TObject);
begin
IdTCPClient1.WriteLn('tablo_güncelle');
end;
client bilgisyarları mesajı göndermak için BroadcastMessage prosedürümüz olsun:
//client bilgisyarlara mesaj gönderir
procedure TForm1.BroadcastMessage;
begin
IdTCPClient1.Host := '192.168.0.18';
IdTCPClient1.Port := 6060;
IdTCPClient1.Connect(5000);
IdTCPClient1.Disconnect;
end;
Kaydet, Değiştir ve Sil Butonlatında bu prosedürü kullanıyoruz.
Kaydet Butonu:
procedure TForm1.Button1Click(Sender: TObject);
begin
ADOTable1.Insert;
ADOTable1.FieldByName('kod').AsString:=Edit1.Text;
ADOTable1.FieldByName('isim').AsString:=Edit2.Text;
ADOTable1.FieldByName('adet').AsString:=Edit3.Text;
ADOTable1.Post;
BroadcastMessage;
end;
Değiştir Butonu:
procedure TForm1.Button2Click(Sender: TObject);
begin
ADOTable1.Edit;
ADOTable1.FieldByName('kod').AsString:=Edit1.Text;
ADOTable1.FieldByName('isim').AsString:=Edit2.Text;
ADOTable1.FieldByName('adet').AsString:=Edit3.Text;
ADOTable1.Post;
BroadcastMessage;
end;
Sil Butonu:
procedure TForm1.Button3Click(Sender: TObject);
begin
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('delete from stok_table where kod='''+ADOTable1.FieldByName('kod').AsString+'''');
ADOQuery1.ExecSQL;
ADOTable1.Requery();
BroadcastMessage;
end;
ana formun Create olayında ini dosyadan parametreler alınır ve IdTCPServer1'e defaultport atanır,burda 6060 kullandık.IdTCPServer1 aktif edilir.
procedure TForm1.FormCreate(Sender: TObject);
begin
IniDosya := TIniFile.Create(ExtractFilePath(Application.ExeName)+'Settings.ini');
try
server:=IniDosya.ReadString('Database','Server','');
sapassword:=IniDosya.ReadString('Database','SaPassword','');
finally
IniDosya.Free;
end;
IdTCPServer1.DefaultPort:=6060;
IdTCPServer1.Active:=true;
end;
IdTCPServer --->Execute olayında,IdTCPClient'ın gönderdiği mesajı yakaladığında
ADOTable1.Requery(); ile tabloyu günceller.
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
mesaj: string;
begin
mesaj:= AThread.Connection.ReadLn;
if mesaj='tablo_güncelle' then
ADOTable1.Requery();
AThread.Connection.Disconnect;
end;
Uygulamanın çalıştığı birden fazla bilgisayardan herhangi birinde tabloya yapılacak bir değişiklik
BroadcastMessage prosedüründe
IdTCPClient1.Host := '192.168.0.10'; ile "192.168.0.10" clientı mesajı alıp tablo güncellenir. uygulamayı kullanan diğer bilgisayarların ip adreslierini bir listboxa alıp döngü ile tek tek bunlara da mesajı gönderebilmek için
BroadcastMessage prosedürünü düzenleyelim:
procedure TForm1.BroadcastMessage;
var
i:integer;
begin
for i:=0 to ListBox1.Count-1 do
begin
IdTCPClient1.Host := ListBox1.Items.Strings[i];
IdTCPClient1.Port := 6060;
IdTCPClient1.Connect(5000);
IdTCPClient1.Disconnect;
end;
end;
Not:
firewall varsa bu yöntem hata verebilir.
2-)
trigger-IdUDPServer kullanarak :

öncelikle sql_event.dll dosyasından
xp_event extended stored procedurünü oluşturmamız gerekir.
xp_event aşağıdaki parametreleri alır:
<hostAdı>,<portNo>,<mesaj>,<KullanıcıAdı>,<KayıtTanımlayıcı>
HostAdı parametresi broadcast adresi olarak kullanılabilir.örneğin 223.1.2.255 (doğrudan broadcast adresi) yada 255.255.255.255 (sınırlı broadcast adresi). yada yerel ağdaki bilgisayar adı da kullanılabilir.
portNo default 3338 kullanılır.
sql_event.dll dosyasını, win32 içine kopyalayın.bu dll in içindeki xp_event stored procedürünü,sql servere aşağıdaki kod ile oluşturun:
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'xp_event' AND type = 'X')
EXEC sp_dropextendedproc 'xp_event'
GO
EXEC sp_addextendedproc xp_event, 'sql_event.dll'
master veritabanında extended stored procedure kısmında oluşacaktır.sql server'de "CREATE PROCEDURE" ile prosedürler oluşturulabildiği .dll dosyasından prosedür/fonksiyon alınabilir.
bir transaction(insert/update/delete) durumunda veritabanının mesaj göndermesi için trigger oluşturmamız gerekir.trigger az önce oluşturduğumuz xp_event sp'sini kullanarak ağa mesajı yayınlar:
insert/update/delete transactionları için ortak bir trigger oluşturalım:
CREATE TRIGGER [trg_tablo_guncelle] ON [stok_table]
FOR INSERT,UPDATE,DELETE
AS
BEGIN
EXEC master..xp_event '192.168.0.255',3338,'tablo_güncelle','',''
END
trigger dan mesajı ağdaki tüm clientlara göndermesi için '192.168.0.255' kullandık.2541 port numarası ,3338 gibi başka bir port no da kullanılabilir. burda dikkat edilecek nokta tigger ın mesajı attığı port ile IdUDPServer ün portu aynı olmalıdır.
ana formun Create'inde IdUDPServer ayarları:
procedure TForm1.FormCreate(Sender: TObject);
begin
IniDosya := TIniFile.Create(ExtractFilePath(Application.ExeName)+'Settings.ini');
try
server:=IniDosya.ReadString('Database','Server','');
sapassword:=IniDosya.ReadString('Database','SaPassword','');
finally
IniDosya.Free;
end;
//IdUDPServer default 3338 portu dinliyor
IdUDPServer1.Active := false;
IdUDPServer1.BufferSize:=10040;
IdUDPServer1.DefaultPort:=3338;
IdUDPServer1.BroadcastEnabled:=true;
IdUDPServer1.ThreadedEvent:=true;
IdUDPServer1.Active := true;
end;
IdUDPServer->OnUdpRead olayında triggerdan ağ sistemine yaılan mesajı yakalayıp
ADOTable1.Requery(); ile tabloyu günceller.
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
DataStringStream: TStringStream;
s: string;
mesaj:string;
begin
DataStringStream := TStringStream.Create('');
try
DataStringStream.CopyFrom(AData, AData.Size);
//IdUDPServer triggerdan mesajı alırsa tabloyu günceller
Memo1.Clear;
Memo1.Lines.Add(DataStringStream.DataString + '" from ' + ABinding.PeerIP + ' on port ' + IntToStr(ABinding.PeerPort));
mesaj :=Memo1.Text ;
if (mesaj='tablo_güncelle') then
ADOTable1.Requery();
s := 'Replied from ' + IdUDPServer1.LocalName + ' to "' + DataStringStream.DataString + '"';
ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, s[1], Length(s));
finally
DataStringStream.Free;
end;
end;
her iki örnek uygulama ekte:
Ynt: MS SQL Server Multiuser Kullanımda Veritabanı Güncelleme Gönderen: FetihlerFatihi Tarih: 28 May 2007 10:12:45
sağol hocam.
ellerin dert görmesin

Ynt: MS SQL Server Multiuser Kullanımda Veritabanı Güncelleme Gönderen: dynamo Tarih: 28 May 2007 10:16:25
teşekkürler fatih hoca.yeni kitabın ile ilgili çalışmalarında başarılar diliyorum.
Ynt: MS SQL Server Multiuser Kullanımda Veritabanı Güncelleme Gönderen: FetihlerFatihi Tarih: 28 May 2007 10:57:04
teşekkür ederim. inşallah