多线程时是否必须锁定数据库连接?

时间:2011-07-02 09:02:19

标签: c# mysql winforms .net-4.0 database-connection

以下是我目前用于数据库交互的类的示例:

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 username=@name 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
        }
    }
}

目前,我没有打开和关闭连接的任何管理,所以它总是检查数据库是否连接,执行操作并关闭它,如UserExist函数所示

考虑到这一点,我注意到我可能会在中间或他们的交易中关闭我自己的连接,因为我在2个不同的线程中使用它。

我怀疑这个简单的课程是否会因任何原因锁定我的申请,使其反应迟钝或者从长远来看会给我带来任何麻烦?

我应该考虑,改进等等?

非常感谢代码示例。

3 个答案:

答案 0 :(得分:2)

每个线程都应该有自己的连接实例,在您的情况下可能是Db的实例。

但是,通过不在Db对象中存储连接,可以更好地解决问题(很多)。最好的模式是仅在using() {}语句中将连接用作局部变量。

目前,您的类应该实现IDisposable(仅适用于try / catch逻辑失败的情况)。

答案 1 :(得分:1)

等待抛出异常然后处理它们不是设计多线程类的好方法。一个好的设计将使用lock语句。使用lock时,您提供关键区域,因此一次只允许一个线程访问资源。一旦一个线程完成其使用,另一个线程就可以继续等等。

例如:

  

因此它将始终检查数据库是否已连接,执行操作并关闭

如果两个线程试图同时进入同一个方法会发生什么?一个线程检查连接是否未设置为继续,并且发现未设置连接以便继续。但是在其进程的中间和连接之前,线程上下文切换切换到另一个线程并暂停第一个线程,第二个线程依次询问是否已设置连接并且它将发现它不是,因此它连接然后继续现在,线程上下文切换切换到第一个线程以继续执行。问题就开始了......

但使用'lock'时情况有所不同;将允许一个且仅一个线程访问标有lock的方法区域。因此,一个线程进入锁定区域并建立连接。那时另一个线程尝试访问该方法,但第一个仍在那里,所以第二个将等待,直到第一个完成其工作,然后它将继续。

答案 2 :(得分:1)

您不必锁定它们,但是:您必须确保2个线程不会同时使用相同的连接。

同步(锁等)是一种方式来做到这一点;隔离是另一种(更好的,IMO)方式。如果两个线程永远不会拥有相同的连接,那么一切都很好。出于这个原因,static连接永远不是一个好主意。