8

正如我以前的問題:How to stay connected to database until screen close?連接池應該比保持連接打開慢得多嗎?

首先,讓我向大家道歉,我不解釋我的情況。

那麼,我的情況是更新至多百條記錄。我用For loop創建一個真正的工作並記錄他們的結果。

private void button1_Click(object sender, EventArgs e) 
{ 
    int i; 
    KeyEventArgs keyEvent = new KeyEventArgs(Keys.Enter); //Create keydown event 

    Performance perf = new Performance(); //Class for measure time and logging 

    perf.Start(); //Start stopwatch 

    for (i = 1; i <= 100; i++) 
    { 
     txtLotNo.Text = i.ToString("0000000000") + "$01"; //Generate input ID 

     txtLotNo_KeyDown(sender, keyEvent); //Fire keydown event 
    } 

    perf.Stop(); //Stop stopwatch 

    perf.Log(frmInvCtrl.appPath,"Stock In (Stay connected)- " + frmInvCtrl.instance); //Logging 
} 

這是一個性能類。

class Performance 
{ 
    private Stopwatch _sw = new Stopwatch(); //Create stopwatch property 

    public double GetWatch 
    { 
     get 
     { 
      return this._sw.ElapsedMilliseconds; 
     } 
    } 

    public void Start() 
    { 
     Stop(); 

     _sw.Reset(); 
     _sw.Start(); 
    } 

    public void Stop() 
    { 
     if (_sw.IsRunning) 
     { 
      _sw.Stop(); 
     } 
    } 

    public void Log(string path,string menu) 
    { 
     string logName = path + "\\Log_" + System.DateTime.Now.ToString("yyyyMMdd") + ".txt"; 
     string logDetail = System.DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss") + " - [" + menu + "] " 
      + "Process 100 record in [" + (((double)_sw.ElapsedMilliseconds/1000)).ToString() + "] seconds"; 

     using(StreamWriter writer = new StreamWriter(logName,true)) 
     { 
      writer.WriteLine(logDetail); //wirtelog 
     } 
    } 
} 

而這些日誌結果

2017/02/19 08:16:05 - [Stock In - On Cloud] Process 100 record in [68.352] seconds 
2017/02/19 08:17:34 - [Stock In - On Cloud] Process 100 record in [70.184] seconds 
2017/02/19 08:20:28 - [Stock In - On Cloud] Process 100 record in [56.66] seconds 
2017/02/19 08:21:34 - [Stock In - On Cloud] Process 100 record in [60.605] seconds 
2017/02/19 08:22:44 - [Stock In - On Cloud] Process 100 record in [68.27] seconds 
2017/02/19 08:24:43 - [Stock In - Network Server] Process 100 record in [46.86] seconds 
2017/02/19 08:26:05 - [Stock In - Network Server] Process 100 record in [31.746] seconds 
2017/02/19 08:26:48 - [Stock In - Network Server] Process 100 record in [31.859] seconds 
2017/02/19 08:27:32 - [Stock In - Network Server] Process 100 record in [31.003] seconds 
2017/02/19 08:28:17 - [Stock In - Network Server] Process 100 record in [40.487] seconds 
2017/02/19 08:32:42 - [Stock In (Stay connected)- On Cloud] Process 100 record in [18.196] seconds 
2017/02/19 08:35:47 - [Stock In (Stay connected)- On Cloud] Process 100 record in [14.721] seconds 
2017/02/19 08:36:30 - [Stock In (Stay connected)- On Cloud] Process 100 record in [15.903] seconds 
2017/02/19 08:37:31 - [Stock In (Stay connected)- On Cloud] Process 100 record in [15.811] seconds 
2017/02/19 08:38:15 - [Stock In (Stay connected)- On Cloud] Process 100 record in [16.4] seconds 
2017/02/19 08:43:08 - [Stock In (Stay connected)- Network Server] Process 100 record in [13.09] seconds 
2017/02/19 08:43:25 - [Stock In (Stay connected)- Network Server] Process 100 record in [13.03] seconds 
2017/02/19 08:43:40 - [Stock In (Stay connected)- Network Server] Process 100 record in [13.051] seconds 
2017/02/19 08:43:55 - [Stock In (Stay connected)- Network Server] Process 100 record in [12.992] seconds 
2017/02/19 08:44:12 - [Stock In (Stay connected)- Network Server] Process 100 record in [14.953] seconds 

我是用連接池實施。但是,在許多記錄情況下,顯示的連接數據庫的這些結果更快。

有沒有適合這種情況的習慣?

編輯:2017年2月21日

下面是當打開表單代碼開放的連接:

private void frm_Load(object sender, EventArgs e) //Open menu 
{ 
    ... //statement 

    frmMain.sqlConn1 = new SqlConnection(); 
    frmMain.sqlConn1.ConnectionString = frmMain.connectionString1; 
    frmMain.sqlConn1.Open(); 

    ... //statement 
} 

更新代碼:

public static long ScanUpdate(string lotNo) 
{ 
    string scanLotNo = ""; 
    int scanIndex = 0; 

    if (!SplitBarcode(lotNo, ref scanLotNo, ref scanIndex)) 
    { 
     //Invalid Barcode data 
     return -919; 
    } 

    //Prepare sql command 
    string updStatus = (frmMain.shelfScan) ? "05" : "10"; 
    string sql = <sql statement> 

    try 
    { 
     using (SqlCommand sqlCmd = new SqlCommand(sql, frmMain.sqlConn1)) //frmMain.sqlConn1 is connection in form_Load() 
     { 
      if (sqlCmd.ExecuteNonQuery() <= 0) 
      { 
       //No row affect 
       //frmMain.sndPlay.Play(); 
       return -99; 
      } 
      else 
      { 
       //Completed 
       return 0; 
      } 
     } 
    } 
    catch 
    { 
     return 99; 
    } 
    finally 
    { 

    } 
} 

和Dispose連接時退出

private void btnBack_Click(object sender, EventArgs e) 
{ 
    frmMain.sqlConn1.Dispose(); 
    this.Close(); 
} 
+2

你確定你在連接上調用'Close()',所以連接返回到池?您是否爲每次更新沒有使用池和打開_new_連接的基準測試時間? –

+0

在(保持連接)測試中,當打開菜單時我在'Form_Load()'上打開連接,並在關閉窗體時打開Dispose。當我打開菜單時,只要打開菜單,我就可以使用此連接更新記錄。沒有(保持連接狀態),我使用''使用'塊,而不像之前的問題那樣在塊之後調用'Close()'。 –

+0

@MitchWheat。你的意思是我應該關閉連接時,完成更新100條記錄,而不是關閉連接每個記錄100次? –

回答

4

從單線程響應性的角度來看,保持連接打開將會更快。連接池的目的是通過在線程之間共享連接池來降低打開新連接的開銷,同時不會消耗共享SQL Server上的過多連接數。

每次連接釋放到連接池並重新使用時,協議棧都會調用sp_resetconnection來清除服務器上的狀態。您可以通過針對SQL Server運行分析器跟蹤來查看此信息。

由於每個進程對於每個連接字符串都有自己的連接池,因此如果在進程內存在連接爭用,您將只能從連接池中受益。

0

有幾個領域,您可以遇到上述代碼的問題。

  • 您正在創建單個SqlConnection實例。
  • 所有的事件處理程序調用引用一個SqlConnection實例的靜態函數。
  • 您的事件處理程序不檢查它們是否在主UI線程上運行。

SqlConnection類將自動池連接下的封面。當您撥打close()函數時,連接只會回到池中。您可以使用連接字符串中的屬性控制池化行爲。通過爲所有函數保留相同的連接對象,你迫使它們被序列化。

這是reference to some connection string properties。看看Connection Lifetime

我會從form_load()功能刪除SqlConnection實例,寫ScanUpdate如下:

public static long ScanUpdate(string lotNo) 
{ 
    string scanLotNo = ""; 
    int scanIndex = 0; 

    if (!SplitBarcode(lotNo, ref scanLotNo, ref scanIndex)) 
    { 
     //Invalid Barcode data 
     return -919; 
    } 

    //Prepare sql command 
    string updStatus = (frmMain.shelfScan) ? "05" : "10"; 
    string sql = <sql statement> 

    try 
    { 
     using (SqlConnection conn = new SqlConection(frmMain.connectionString1)) { 
      SqlCommand sqlCmd = new SqlCommand(sql, conn); 
      if (sqlCmd.ExecuteNonQuery() <= 0) 
      { 
       //No row affect 
       //frmMain.sndPlay.Play(); 
       return -99; 
      } 
      else 
      { 
       //Completed 
       return 0; 
      } 
      conn.Close(); 
     }    
    } 
    catch 
    { 
     return 99; 
    } 
} 

爲了您*_Click事件處理函數,請務必檢查,以檢查事件需要被重新調用:

private void button1_Click(object sender, EventArgs e) 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new EventArgsDelegate(button1_Click), new object[] { sender, ea }); 
    } 

    // Do some stuff 
} 

有關事件處理的更詳細見this answer