SQLServer - "Bağlantı başarısız oldu" problemi hk.

MS SQL Server veritabanı ve SQL komutlarıyla ilgli sorularınızı sorabilirsiniz. Delphi tarafındaki sorularınızı lütfen Programlama forumunda sorunuz.
Cevapla
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4718
Kayıt: 09 Ara 2003 08:13
Konum: Ankara
İletişim:

SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen mrmarman » 09 Ağu 2010 12:06

Merhaba.

- MS-SQLServer veritabanına AdoConnection ile bağlı iken
1. Sunucu bilgisayar veya sunucu bilgisayardaki SQLServer restart edildiğinde
2. Sorgu sırasında AĞ'da sorun olduğunda...

... istemci (Client) makinelerde "Bağlantı başarısız oldu" hatası aldığımız durum gerçekleşiyor. AdoConnection'un bağlantı durumunu kontrol ettiğimizde halen Connected görünüyor.

- Zaten bunu DBGrid'lerdeki verinin ekranda görünmeye devam etmesinden anlıyoruz, keza AdoConnection Connected false olduğunda bağlı tüm AdoQuery'ler kapanıyor.

- Bu durumda AdoConnection'un Connected = True durumunu bozmadan yeniden SQLServer ile bağlantıdaki bu hatayı tamir edebilir miyiz ? Sorunun özü budur ... :?:

- MSSQLServer Express kurulu SUNUCU bir bilgisayara AĞ üzerinden bağlantı kurulup bilgi girişi ve/veya sorgu yapılıyor. Master/Detail ilişkili iki tablo mevcut.

- Çalışma sırasında Master tablodaki veri DBGrid'den seçildikçe Detail tablodaki veri sorgulanarak diğer DBGrid'de sonuç ekrana yansıyor.

- Master tablo görüntüleniyor ve Detail tablo da görüntüleniyor iken, ağ kablosunu çektiğinizde beklenen şekilde; Master tablodan yapılan seçim doğal olarak detay tabloda detaylandırılamıyor ve "Bağlantı başarısız oldu" şeklinde bir hata alıyoruz. Bu da doğal. Buna diyecek bişeyim olamaz.

- Şimdi yazılım halen çalışıyor, ağ kablosunu tekrar yerine taktık ve ağ bağlantısı sağlandı. Master tablo hala açık, detay göremiyorduk. Master tablodan seçim yaptığımızda herşey normale dönmesini beklerken "Bağlantı başarısız oldu" hatası devam ediyor.

- Sorgulardan önce (özellikle master / detail sorgularda)

Kod: Tümünü seç

if AdoConnection.Connected THEN begin .. end;
[/b] şeklinde blok içine alarak bağlantıyı sınayarak işlem yapmama rağmen bu sorguda da yanlışlıkla Connected algılıyor ki yine aynı hata mesajıyla karşılaşıyorum.

- ANCAK

Kod: Tümünü seç

AdoConnection.Connected := False;
deyip ardından bağlantı kurduğumda sorun ortadan kalkıyor.

- Bu durumda da aynı AdoConnection'a bağlı açık diğer arkadaki formlardaki tabloların açık olduğu AdoQuery'lerin de Active'liği düşüyor ve hepsinin ayrı ayrı yeniden açılarak eski kayıt nolarına Locate ettirmek gereği doğuyor.

Bu sorunla muhakkak karşılaşan olmuştur. Çözümleri paylaşırsanız sevinirim. Kendimce gereğinden uzun yollu bir çözüme gitmek istemiyorum. :idea:
Resim Resim

thelvaci
Kıdemli Üye
Mesajlar: 765
Kayıt: 11 Tem 2010 06:17
Konum: Istanbul
İletişim:

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen thelvaci » 20 Ağu 2010 03:25

Muarrem beyin sorusuna istinaden özel mesaj ile paylaştığım bilgilerimi genel olarak paylaşmak belki başka arkadaşlarında istifadesine olacaktır.

Merhabalar, hatayı try/except bloğunda kontrol etmek gibi olacak evet ancak düşünebiliyormusunuz projenizin her yerinde sql çağrımları için try/except kullanacağınızı ! Bu son derece zor bir durum olurdu. Benim çözümüm şu şekilde; Network'ün durumunu takip eden bir thread var. Bu thread belirlediğiniz zaman dilimlerinde kontrol yapıyor ve makinadan ethernet kablosunu çıkarttığınızı, yeniden taktığınızı, etherneti disable ettiğinizi vb anlayıp ona göre işlem yapabiliyor. Şimdi mantıken, ethernet kartınızdan mütevellit bir sıkıntı hasıl olduğunda bağlantınız zaten kopmuş olacaktır. Ancak TADOConnection bunu bilmeyecektir. Bu durumda biz bağlantı yeniden sağlandığında TADOConnection'a Open diyoruz. Bunun aksi bir durum fiziksel olarak zaten mümkün değil. Yani kopmuş bir bağlantıyı mecburen yeniden Open etmek durumundayız.

İkinci thread'im ise; ethernet bağlantısında bir sorun olmamasına rağmen Sql Server'ın stop edilebilme ihtimaline karşı görev yapıyor. Bu thread içinde; Sql Server 2005'e erişim sağlayan kütüphanemin bir metodu olan ConnectionCount property'sini kontrol ediyorum. Eğer bu property'den bir değer alabiliyor isem Sql Server yerinde duruyor demektir, aksi durumda Sql server kapalı yada erişilemez durumdadır'a kanaat getiriyorum. Bu durumda, yani Sql server'a erişilememe durumunda yine bizim TADOConnection nesnemiz aslında bir fiziksel bağlantıya sahip değildir. Sql Server stop olmuştur ancak TADOConnection bundan haberdar olamamıştır. Bu durumda Connection'ın yeniden sağlanması icap eder.

Ben projemde bu thread'ler ile bir şekilde Disconnect yakalarsam; önce bir bilgi mesajı veriyor ardından ekrandaki tüm formları gizliyorum ki kullanıcılar bir sorun olduğunun farkına varabilsin ve gereken çözüm için harekete geçebilsin, aynı zamanda bağlantı fiziksel olarak koptuğu için bağlantı üzerinden işlem yapmaya çalışmasın. Ve bağlantı yeniden sağlandığında ilgili açık formları ekrana yeniden getiriyorum tabii ADOConnection'ları Open ederek. Böylece kullanıcı hiçbirşeyden feragat etmeden kaldığı noktadan devam edebiliyor.

Buyrun size kodları aktarayım, ondan sonra üzerinde yine sohbet edebiliriz gerek görülür ise;

Kod: Tümünü seç

      
      TNetworkWatcher = class(TThread)
      private
        fOnConnected,
        fOnDisconnected : TNotifyEvent;

        OldValue,
        NewValue,
        fControlTime : Integer;

        function GetStatus : String;

        procedure DoConnect;
        procedure DoDisconnect;
      protected
        procedure Execute; override;
      public
        constructor Create(const ControlTime : Integer = 1000);

        property OnConnected    : TNotifyEvent read fOnConnected write fOnConnected;
        property OnDisconnected : TNotifyEvent read fOnDisconnected write fOnDisconnected;
      end;

      TSQLServerWatcher = class(TThread)
      private
        fConnected : Boolean;
        fConnectionCount : Integer;
        anArray : array of TForm;

        procedure Connect;
        procedure Disconnect;

        procedure SetConnected(const Value : Boolean);
        function GetConnected : Boolean;

        property Connected : Boolean read GetConnected write SetConnected;
      protected
        procedure Execute; override;
      public
        constructor Create;
        destructor Destroy; override;
      end;

    implementation

    uses
      WbemScripting_TLB,
      ActiveX;

    { TNetworkWatcher }

    constructor TNetworkWatcher.Create(const ControlTime : Integer = 1000);
    begin
      inherited Create(true);
      FreeOnTerminate := true;

      fControlTime := ControlTime;
    end;

    procedure TNetworkWatcher.DoConnect;
    begin
      if Assigned(fOnConnected) then fOnConnected(Self);
    end;

    procedure TNetworkWatcher.DoDisconnect;
    begin
      if Assigned(fOnDisconnected) then fOnDisconnected(Self);
    end;

    procedure TNetworkWatcher.Execute;
    var
      sVal : String;
      List : TStrings;

      iStatus,
      iCounter : Integer;
    begin
      inherited;

      CoInitialize(nil);

      OldValue := 0;
      NewValue := 0;

      try
        while not Terminated do
        begin
          sVal := GetStatus;
          List := TStringList.Create;

          try
            ExtractStrings([Char(13)], [], PChar(sVal), List);
            for iCounter := 0 to List.Count - 1 do
            begin
              iStatus := StrToIntDef(List[iCounter], -1);
              NewValue := iStatus;

              if OldValue <> NewValue then
                case iStatus of
                  0,
                  7 : Synchronize(DoDisconnect); // Media disconnected and Disconnected
                  1 : ; // 'Connecting..'
                  2 : Synchronize(DoConnect);
                  3 : ; //'Disconnecting..';
                  4 : ; //'Hardware not present';
                  5 : ; //'Hardware disabled';
                  8 : ; //'Authenticating';
                  9 : ; //'Authentication succeeded';
                  else ; // '?????????????';
                end;

                OldValue := NewValue;
            end;
          finally
            List.Free;
          end;

          Sleep(fControlTime); // Belirtilen saniyede bir kontrol işlemi yapılsın..
        end; // while not Terminated do

      finally
        CoUnInitialize;
      end;
    end;

    function TNetworkWatcher.GetStatus: String;
    var
      Locator : ISWbemLocator;
      Services: ISWbemServices;
      SObject : ISWbemObject;
      ObjSet  : ISWbemObjectSet;
      SProp   : ISWbemProperty;
      Enum    : IEnumVariant;
      Value   : Cardinal;
      TempObj : OleVariant;

      qry,
      tmp     : String;
    begin
      Result := '';
      qry := 'SELECT * FROM Win32_NetworkAdapter WHERE PNPDeviceID LIKE ' + Char(39) + 'PCI\\%' + Char(39);

      try
        Locator := CoSWbemLocator.Create;

        Services :=  Locator.ConnectServer('', 'root\cimv2', '', '', '','', 0, nil);
        ObjSet := Services.ExecQuery(qry, 'WQL',
        wbemFlagReturnImmediately and wbemFlagForwardOnly , nil);
        Enum :=  (ObjSet._NewEnum) as IEnumVariant;

        while (Enum.Next(1, TempObj, Value) = S_OK) do
        begin
          SObject := IUnknown(tempObj) as ISWBemObject;
          SProp := SObject.Properties_.Item('NetConnectionStatus', 0);

          if VarIsNull(SProp.Get_Value) then Result := ''
          else
          begin
            tmp := SProp.Get_Value;
            Result :=  Result + tmp + #13#10;
          end;
        end;
      except on Exception do Result := '';
      end;
    end;

    { TSQLServerWatcher }

    constructor TSQLServerWatcher.Create;
    begin
      inherited Create(true);
      FreeOnTerminate := true;
      fConnected := true;

      Resume;
    end;

    procedure TSQLServerWatcher.Connect;
    var
      iCounter : Integer;
    begin
      _dmMain.connMain.Open;
      _dmMain.connLog.Open;

      ShowAlertWindow('Ana makinaya yeniden bağlanıldı...');
      frmMain.Enabled := true;

      if anArray <> nil then
        for iCounter := Low(anArray) to High(anArray) do
        begin
          SetWindowPos(anArray[iCounter].Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW);
          SendMessage(anArray[iCounter].Handle, CM_SHOWINGCHANGED, 0, 0);
        end;

      anArray := nil;

      if NetworkWatcher <> nil then
        NetworkWatcher.Resume;

    //  frmMain.sBar.Panels[4].Text := Format('Bağlantı Sayısı:%d', [fConnectionCount]);
    end;

    procedure TSQLServerWatcher.Disconnect;
    var
      iCounter : Integer;
    begin
      if NetworkWatcher <> nil then
        NetworkWatcher.Suspend;

      for iCounter := 0 to Screen.FormCount - 1 do
        if (Screen.Forms[iCounter] <> Application.MainForm) and (Screen.Forms[iCounter].Visible) then
        begin
          SetLength(anArray, Length(anArray) + 1);
          anArray[High(anArray)] := Screen.Forms[iCounter];

          if Supports(anArray[iCounter], IAbortable)
          then (anArray[iCounter] as IAbortable).AbortWork(0);

          ShowWindow(anArray[iCounter].Handle, SW_HIDE);
        end; // if (Screen.Forms[iCounter] <> Application.MainForm) and (Screen.Forms[iCounter].Visible) then

      _dmMain.connMain.Close;
      _dmMain.connLog.Close;

      ShowAlertWindow('Ana makina ile bağlantı sorunu yaşanıyor..!');
      frmMain.Enabled := false;
    end;

    procedure TSQLServerWatcher.Execute;
    begin
      inherited;

      while not Terminated do
      begin
        if SqlServer <> nil then
        begin
            try
              fConnectionCount := SqlServer.ConnectionCount;
              if not Connected then Connected := true;
            except
              if Connected then Connected := false;
            end;
        end;

        Sleep(2000); // 2 saniyede bir kontrol et..
      end;
    end;

    function TSQLServerWatcher.GetConnected: Boolean;
    begin
      Result := fConnected;
    end;

    procedure TSQLServerWatcher.SetConnected(const Value : Boolean);
    begin
      if Value <> fConnected then
      begin
        fConnected := Value;

        case fConnected of
          true : Synchronize(Connect);
          false: Synchronize(Disconnect);
        end;
      end;
    end;

    destructor TSQLServerWatcher.Destroy;
    begin
      anArray := nil;

      inherited;
    end;

Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4718
Kayıt: 09 Ara 2003 08:13
Konum: Ankara
İletişim:

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen mrmarman » 21 Ağu 2010 04:28

Teşekkürler.
İlettiğim soryu ve cevapları da burada ben paylaşayım.
@mrmarman yazdı:Merhaba..

Yanlış anlamış olabilirim, beni mazur görün. Aslında bu bahsettiğiniz çözüm sizce de hatayı try / except bloğuna almak gibi bir çözüm olmayacak mı ? Bağımsız bir thread ile farklı bir connection ile sqlserver'a bağlayıp, periyordik boş sorgu yaptırmak (koptuğunu anlamak için) bu bağlantının hataya düşmesini beklemekt, buna göre daha önce bahsettiğim benzer stratejiyi halukarda geliştirerek veritabanı close open yapıp, tabloları requery ederek eski konumlara locate ettirmek.

Mümkün müyü aradığım asıl nokta bağlantıyı kapatıp / açmak gereği olmadan yola devam edebilmek idi ama çözümünüzü görene kadar bekliycem.

teşekkürler.
Mesajınıza değin herhangi bir çözüm yolu bulamayınca kendi çözümümü şu olmuştu.

internetteki çözümlerin bir çoğu, timeout / sistem güç ayarları vb. gerekçeli sunucu bilgisayardaki kapanmaları engellemek üzerine olduğunu gördüm. Genelinde timer koyup boş / basit sorgu yaptırarak canlı tutmaya yönelik.

Kolay bir yolu varsa da kendimce bu kolay yola cevap bulamayınca, sancılı da olsa mevcut sistemde çözümümü şöyle ürettim.

- Sistemde Server ile Client bilgisayarları (1 ana server, 3 ara server ile 64 client bilgisayardan oluşan yapıdır) veritabanı aktiviteleri için TCP üzerinden hali hazırda kurduğum haberleşme protokolüne herhangi bir bilgisayar bu hata ile karşılaşırsa genele E440 gibi bir hata mesajı yayınlıyor. ( ERP görevlendirme tabloları olduğundan o master kayıt girilir de görevlendirme kartı açılmışsa her bir göreve özel olarak ilgili client makinelere personel görevlendirmesi için alarm meydana gelmesi adına hazırladığım altyapıdır.)

- Yazılım modüllerinin her birindeki tabloların afterscroll olaylarına konumlanan kaydın KaySiraNo alanını global değişkenlerde tutmasını sağladım. Çok sayıda farklı modül ve tablo olduğundan çok zorlandım.

- Bu hata mesajı TCP'den düşerse açık tablolar ( DataModule üzerinden bakılıyor ) bir bir dolaşılarak 4 ado connection close / open yapılıyor ve kaysirano'su (-1)'den farklı olan tablolar yeniden requery edilerek her bir global değişkene göre LOCATE ediliyor.

Sizin mesajda belirttiğiniz
@thelvaci yazdı:... Şimdi mantıken, ethernet kartınızdan mütevellit bir sıkıntı hasıl olduğunda bağlantınız zaten kopmuş olacaktır. Ancak TADOConnection bunu bilmeyecektir. Bu durumda biz bağlantı yeniden sağlandığında TADOConnection'a Open diyoruz. Bunun aksi bir durum fiziksel olarak zaten mümkün değil. Yani kopmuş bir bağlantıyı mecburen yeniden Open etmek durumundayız.
ifadesinden de açık olarak belirttiğiniz üzere AdoConnection'un ve dolayısı ile bağşı tüm tabloların kapanıp / açılması ile tablo konumlarına yeniden konumlanmaktan başka yapacak bişey kalmıyor.
Resim Resim

thelvaci
Kıdemli Üye
Mesajlar: 765
Kayıt: 11 Tem 2010 06:17
Konum: Istanbul
İletişim:

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen thelvaci » 22 Ağu 2010 06:42

Evet maalesef, bağlantının yeniden açılması icap ediyor. Bağlantı her iki durumda da fiziksel olarak kopuyor çünkü.

nodetail
Üye
Mesajlar: 49
Kayıt: 04 Eki 2008 09:30

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen nodetail » 07 Kas 2018 05:48

Konu çok eski ancak farklı kaynak bulamadım;
Bu sorunu sadece uyku modu için daraltıp farklı bir çözüm bulabilir miyiz.

Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3014
Kayıt: 17 Nis 2006 07:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen sabanakman » 07 Kas 2018 06:08

Kullandığınız bağlantı bileşeni ADO değilse bununla ilgili bir olay tanımı olabilir. Tam olarak denemedim ama örnek olarak FireDAC için OnRecover olayına

Kod: Tümünü seç

procedure TForm1.FDConnection1Recover(ASender, AInitiator: TObject;
  AException: Exception; var AAction: TFDPhysConnectionRecoverAction);
begin
  AAction:=faRetry;
end;
ataması yapılabilir.

UniDAC bileşeni olan UniConnection bileşeni için ise;
1-UniConnection1.Options.LocalFailOver:=True,
2-Uses'da MemData unitinin tanımlı olması,
3-ConnectionLost olayına

Kod: Tümünü seç

procedure TForm1.UniConnection1ConnectionLost(Sender: TObject;
  Component: TComponent; ConnLostCause: TConnLostCause;
  var RetryMode: TRetryMode);
begin
  RetryMode:=rmReconnectExecute;
end;
yazılmalıdır.

Bunlar kopan bağlantıyı tekrar sağlayan ek özelliklerdir.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .

nodetail
Üye
Mesajlar: 49
Kayıt: 04 Eki 2008 09:30

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen nodetail » 08 Kas 2018 04:56

Bağlantı AdoConnection ve AdoQuery

Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3014
Kayıt: 17 Nis 2006 07:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: SQLServer - "Bağlantı başarısız oldu" problemi hk.

Mesaj gönderen sabanakman » 10 Kas 2018 06:10

Bağlantıyı kapatıp açmayı organize etmek biraz size düşüyor o zaman. ADO ile bu konularda işlem yapmak mümkün müdür mümkünse ne kadar efor gerekiyor bilemiyorum ama imkanınız varsa FireDAC a geçmeniz daha kolay olabilir.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .

Cevapla