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