2011-11-09 30 views
0

有沒有什麼方法可以使數據庫連接保持打開狀態並準備在運行時使用? 我們的WCF服務應該保持連接。 現在我們有代碼,類似於這樣的代碼:保持有效的數據庫連接在沒有本地池的情況下保持活動

// This is the class of objects that has connections within. 
[DataContract] 
public class SomeObj 
{ 
    [DataMember] 
    public string Name { get; set; } 

    public OracleConnection Conn { get; set; } 
} 

// Dictionary of SomeObjs 
private static Dictionary<string, SomeObj> myObjs = new Dictionary<string, SomeObj>(); 

當服務正在啓動,還連接從自己的配置文件中的所有數據庫裏面的連接字符串。但是如你所知,連接可能會被破壞,無法使用,甚至最終無法訪問。因此,爲了消除這個問題,我們有一個檢查在配置所有連接特殊的計時器:

// Setup timer method. Timer will fire every minute. 
    static private void CreateTimer() 
    { 
     Timer Timer1 = new System.Timers.Timer(); 
     Timer1.Enabled = true; 
     Timer1.Interval = 60000; 
     Timer1.Elapsed += new System.Timers.ElapsedEventHandler(Timer1_Elapsed); 
    } 

    static private void Timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
      Parallel.ForEach(Program.config.Root.Elements("databases"), el => 
      { 
       try 
       { 
        Program.OpenConnection(el.Attribute("name").Value); 
       } 
       catch (Exception exc) 
       { 
        Console.WriteLine(DateTime.Now.ToString() + " " + exc);       
       } 
      }); 

      // This is old way we checks connections consistently 
      //foreach (XElement element in Program.config.Root.Elements("databases")) 
      //{ 
      // try 
      // {     
      //  AServ.OpenConnection(el.Attribute("name").Value);     
      // } 
      // catch (Exception exc) 
      // { 
      //  Console.WriteLine(DateTime.Now.ToString() + " " + exc);     
      // } 
      //}     
    } 


    public static bool OpenConnection(string name) 
    { 
     // if connections exactly doesn't exists 
     if (!myObjs.ContainsKey(name)) 
      { 
       XElement el = (from t in config.Root.Elements("databases") 
           where t.Attribute("name").Value == name 
           select t).FirstOrDefault(); 
       if (el == null) 
       { 
        lock (myObjs) 
        { 
         myObjs.Remove(name);        
        } 
        return false; 
       } 
       lock (myObjs) 
       { 
        myObjs.Add(name, new SomeObj { Conn = new OracleConnection { ConnectionString = el.Attribute("connectionString").Value } }, Name = el.Attribute("name").Value); 
       } 
      } 
      // if connection broken 
      if ((myObjs[name].Conn.State != ConnectionState.Open || !myObjs[name].Conn.Ping()) && myObjs.ContainsKey(name)) 
      { 
       try 
       { 
        // Trying to get it alive 
        lock (myObjs) 
        { 
         myObjs[name].Conn.Close(); 
         myObjs[name].Conn.Open(); 
        } 
       } 
       catch (Exception e) 
       { 
        if (!myObjs.ContainsKey(name)) 
         return false; 

        lock (myObjs) 
        { 
         myObjs.Remove(name); 
        } 

        return false;       
       } 
       Console.WriteLine(DateTime.Now.ToString() + " " + myObjs[name].Conn.ConnectionString);      
      } 

     return true; 
    } 

還有一件事你應該知道,夥計們,是我們如何使用保持在方法本身的連接:

private static int GetParameterValue(string name, int id) 
    { 
     // if we don't get parameter value at the moment because broken connection 
     if (!OpenConnection(name)) 
      return -1; 

     // assuming connection is OK and getting the parameter value 
     string parameterQuery = @"select GetInfo(:id) from dual"; 
     OracleCommand parameterCommand = new OracleCommand(parameterQuery, myObjs[name].Conn); 
     parameterCommand.Parameters.Add("id", id);    
     return Convert.ToInt32(parameterCommand.ExecuteScalar()); 
    } 

問題是,有時第一次定時器檢查不能及時完成,第二次定時器檢查在第一次運行時開始,第一次運行時。它會給堆內存泄漏帶來一些奇怪的錯誤(我認爲是這樣)。另一個問題是,即使我們開發單一設計模式,只有一個檢查及時,檢查可能掛起和另一個檢查永遠不會被解僱(因爲打開連接需要一個長時間的高價時間的一些數據庫。我不知道爲什麼它發生了,但我們試圖添加Connection timeout=30;,但老實說我不記得給它正確的結果與否,當然不是。)。

然後這個服務及時運行,它運行時需要儘可能多的內存。我用這段代碼嘗試了很多操作,甚至在代碼中某處遇到了一次死鎖(幾乎100%的CPU負載)。

是的,我知道本地ADO .NET池,但我們不能使用它,因爲我們有巨大的遺留代碼庫,以上述方式工作,應該以某種方式改進現有的檢查邏輯。

那麼告訴我你的想法我們如何在沒有合併的情況下及時活着連接? 我需要一些可以使用盡可能少的內存(現有代碼佔用更多內存,因爲它正在運行)的方式,並且可以快速處理小代碼更改。

任何幫助非常感謝!真的希望你的幫助stackoverflow社區!

我想到了使用特殊線程來檢查連接的最終週期與Thread.Sleep(60000)。但我不確定。

ADO .NET提供程序是Devart dotConnect for Oracle。數據庫是Oracle 9-11(取決於服務器),C#.NET Framework 4的

回答

1
  1. 尋找您的註冊表位置HKLM \ SOFTWARE \ ORACLE Oracle主(例如C:\ ORACLE \客戶端\ 10G)
  2. 打開網絡\ admin目錄的ORACLE_HOME下(例如C:\ ORACLE \客戶端\10克\網絡\ ADMIN)
  3. 打開(或創建如果它不存在)一個名爲SQLNET.ORA
  4. 添加以下行: SQLNET.EXPIRE_TIME = 1

會發生什麼情況是,將每隔1分鐘向數據庫服務器發送一次探測,這將導致連接保持活動狀態。

希望它有幫助。 丹尼爾

+1

,基本上是錯誤的...的'EXPIRE_TIME'設置僅服務器端和幫助服務器檢測到死連接(見http://www.orafaq.com/wiki/Sqlnet.ora) – Yahia

+0

那麼你下次你打電話給別人時應該更好地檢查自己;根據[Oracle的文檔](http://download.oracle.com/docs/cd/B19306_01/network.102/b14213/sqlnet.htm)以及我個人的經驗,它適用於客戶端和服務器端。 –

+0

from http://download.oracle.com/docs/cd/B19306_01/network.102/b14213/sqlnet.htm#sthref370:此參數主要用於數據庫服務器,該服務器通常在任何時間處理多個連接。 – Yahia