Arşiv Anasayfa SQL Server
Sayfalar: 1
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 Smiley
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