2011-07-02 88 views
2

這是我目前使用的數據庫交互類的一個示例:多線程時,我是否必須鎖定數據庫連接?

using System; 
using System.Data; 
using System.Collections.Generic; 

// Libraries 
using log4net; 
using log4net.Config; 
using MySql.Data.MySqlClient; 

namespace AIC 
{ 
    class DB 
    { 
     private static readonly ILog _logger = LogManager.GetLogger(typeof(DB)); 
     private MySqlConnection _connection; 
     private MySqlCommand _cmd; 
     private string _server; 
     private string _database; 
     private string _username; 
     private string _password; 

     //Constructor 
     public DB(string server, string database, string username, string password) 
     { 
      log4net.Config.XmlConfigurator.Configure(); 

      _server = server; 
      _database = database; 
      _username = username; 
      _password = password; 

      _connection = new MySqlConnection(string.Format("SERVER={0};DATABASE={1};UID={2};PASSWORD={3};charset=utf8;", _server, _database, _username, _password)); 
     } 

     public bool TestConnection() 
     { 
      try 
      { 
       _connection.Open(); 
       _connection.Close(); 
       _logger.Info("Connection test, passed..."); 
       return true; 
      } 
      catch (MySqlException ex) 
      { 
       _logger.Error(ex.ToString()); 
       return false; 
      } 
     } 

     //open connection to database 
     private bool Open() 
     { 
      try 
      { 
       if (_connection.State != ConnectionState.Open) 
        _connection.Open(); 
       _logger.Info("Starting connection to database..."); 
       return true; 
      } 
      catch (MySqlException ex) 
      { 
       _logger.Error(ex.ToString()); 
       return false; 
      } 
     } 

     //Close connection 
     private bool Close() 
     { 
      try 
      { 
       if (_connection.State != ConnectionState.Closed) 
        _connection.Close(); 
       _logger.Info("Closing connection to database..."); 
       return true; 
      } 
      catch (MySqlException ex) 
      { 
       _logger.Error(ex.ToString()); 
       return false; 
      } 
     } 

     // Some basic functions 
     public bool UserExist(string user) 
     { 
      string query = "SELECT user_id FROM users WHERE [email protected] LIMIT 1"; 
      if (this.Open()) 
      { 
       try 
       { 
        // Assign the connection 
        _cmd = new MySqlCommand(query, _connection); 

        // Prepare to receive params 
        _cmd.Prepare(); 

        // Fill up the params 
        _cmd.Parameters.AddWithValue("@name", user); 

        // returned count bool 
        bool result = Convert.ToInt32(_cmd.ExecuteScalar()) > 0; 

        // Close connection 
        this.Close(); 
        return result; 
       } 
       catch (MySqlException ex) 
       { 
        _logger.Error(ex.ToString()); 
        this.Close(); 
        return false; 
       } 
      } 
      else 
      { 
       _logger.Error("You must be connected to the database before performing this action"); 
       return false; 
      } 
     } 

     public bool AddUser(string user) 
     { 
      // .... add user to database 
     } 

     public bool DelUser(string user) 
     { 
      // .... del user from database 
     } 

     public int CountUsers() 
     { 
      // .... count total users from database 
     } 
    } 
} 

目前,我沒有開任何管理和關閉連接,因此它總是會或請檢查是否數據庫連接不,請執行操作並關閉它,如用戶列表功能中所顯示的

考慮到這一點,它引起了我的注意,我可能正在關閉自己的中間連接或他們的事務,因爲我在2個不同的線程中使用它。

我的疑惑是這個簡單的類可能會鎖定我的應用程序,出於任何原因使它無響應或長期導致我的麻煩?

我該怎麼考慮,改進等?

將不勝感激代碼示例。

回答

2

每個線程應該有自己的連接實例,在你的情況下可能是一個Db的實例。

但是,通過不在你的Db對象中存儲連接,問題將得到解決(很多)。最好的模式是僅在using() {}聲明中使用連接作爲局部變量。

目前,您的類應該實現IDisposable(僅適用於您的try/catch邏輯失敗的情況)。

+0

Henk Holterman如此基本,如果我將這些函數放在同一個名字空間中調用數據庫,而不是在我的情況下使用db對象,那麼它們就可以了嗎? – Prix

+0

命名空間不起作用。只要保持連接儘可能地方。刪除_connection字段。 –

1

等待拋出異常並處理它們並不是設計多線程類的好方法。一個好的設計將使用lock聲明。當使用lock時,您將提供關鍵區域,因此在一次只允許一個線程訪問資源。一旦一個線程完成其使用,另一個線程可以繼續,等等。

例如:

所以它總是會請檢查是否數據庫連接與否,執行的行動,並密切

會發生什麼,如果兩個線程試圖進入相同的方法同時?一個線程檢查連接是否未設置爲繼續,並且發現連接未設置,因此繼續。但是在進程的中間和連接之前,線程上下文切換切換到另一個線程並暫停第一個線程,第二個線程反過來詢問連接是否被設置,並且它會發現它不是,所以它連接並繼續。現在線程上下文切換切換到第一個線程繼續執行。並且問題開始...

但是,使用「鎖定」時情形不同;一個且只有一個線程將被允許訪問標有lock的方法區域。所以一個線程進入鎖區域並建立連接。那時另一個線程嘗試訪問該方法,但第一個線程仍然存在,所以第二個線程將等待第一個線程完成其工作,然後繼續。

1

您不必鎖定它們,但是:您必須確保2個線程不會同時使用相同的連接。

同步(鎖等)是一個方式做到這一點;隔離是另一種(更好的,IMO)的方式。如果兩個線程永不相同的連接,那麼一切都很好。由於這個原因,一個static連接永遠不是一個好主意。

+0

示例代碼中的_connection_不是靜態的。只是記錄器。 –

+0

@亨克我沒有說這是;這是我所提出的觀點的必然結果,而不是對這個例子的討論。 –

+0

@MarcGravell你能解釋/舉一個你隔離的意思嗎? – DevDave

相關問題