多线程时是否必须锁定数据库连接
本文关键字:锁定 数据库连接 是否 多线程 | 更新日期: 2023-09-27 18:01:00
以下是我当前用于数据库交互的类的示例:
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函数所示。
考虑到这一点,我注意到我可能会在中间关闭我自己的连接或它们的事务,因为我在两个不同的线程中使用它。
我的疑问是,这个简单的类是否会因为任何原因锁定我的应用程序,使其没有响应,或者从长远来看给我带来任何麻烦?
我应该考虑什么、改进什么等等。?
非常感谢代码示例。
每个线程都应该有自己的连接实例,在您的情况下可能是Db
的实例。
但是,如果完全不在Db对象中存储连接,问题会得到更好的解决。最好的模式是在using() {}
语句中只使用连接作为局部变量。
目前,您的类应该实现IDisposable(仅用于try/catch逻辑失败的情况(。
等待抛出异常然后处理它们不是设计多线程类的好方法。使用CCD_ 3语句将是一个好的设计。当使用lock
时,您提供了关键区域,因此一次只允许一个线程访问资源。一旦一个线程完成使用,另一个线程就可以继续,依此类推
例如:
因此,它将始终检查数据库是否连接,执行操作并关闭
如果两个线程试图同时进入同一个方法,会发生什么?一个线程检查连接是否未设置为继续,并发现连接未设置,因此继续。但在其进程的中间,在连接之前,线程上下文切换切换到另一个线程并暂停第一个线程,第二个线程反过来询问连接是否已设置,它会发现没有,所以它连接并继续。现在,线程上下文切换切换到第一个线程以继续执行。问题开始了。。。
但使用"锁定"时,情况有所不同;将只允许一个线程访问用lock
标记的方法区域。因此,一个线程进入锁定区域并建立连接。此时,另一个线程尝试访问该方法,但第一个线程仍在,因此第二个线程将等待,直到第一个线程完成其工作,然后继续。
您不必锁定它们,但可以:您必须确保两个线程不会同时使用同一连接。
同步(锁定等(是一种方式;隔离是另一种(更好的,IMO(方式。如果两个线程从不具有相同的连接,那么一切都是好的。因此,static
连接从来都不是一个好主意。