线程安全数据访问对象C#
我试图创建一个线程安全的数据访问层(有点像SQL数据客户端包装器)。我应该采取哪些步骤来确保线程安全,同时最大限度地提高性能 例如,如果我在sqlConn关闭连接之前添加了一个锁(因为它实现了IDisposable);如果连接处于事务或查询的中间位置,则如何?< /P> 总之,我正在尝试实现一个线程安全的解决方案;但同时,我不想冒任何重大异常或任何延迟的风险。有什么方法可以让我对结束线程进行优先级排序吗线程安全数据访问对象C#,c#,sql,multithreading,sqlclient,C#,Sql,Multithreading,Sqlclient,我试图创建一个线程安全的数据访问层(有点像SQL数据客户端包装器)。我应该采取哪些步骤来确保线程安全,同时最大限度地提高性能 例如,如果我在sqlConn关闭连接之前添加了一个锁(因为它实现了IDisposable);如果连接处于事务或查询的中间位置,则如何?< /P> 总之,我正在尝试实现一个线程安全的解决方案;但同时,我不想冒任何重大异常或任何延迟的风险。有什么方法可以让我对结束线程进行优先级排序吗 public class SQLWrapper : IDisposable {
public class SQLWrapper : IDisposable
{
private SqlConnection _sqlConn;
public SQLWrapper(string serverName_, string dbName_)
{
SqlConnectionStringBuilder sqlConnSB = new SqlConnectionStringBuilder()
{
DataSource = serverName_,
InitialCatalog = dbName_,
ConnectTimeout = 30,
IntegratedSecurity = true,
};
sqlConnSB["trusted_connection"] = "yes";
this.start(sqlConnSB.ConnectionString);
}
public SQLWrapper(string connString_)
{
this.start(connString_);
}
private void start(string connString_)
{
if (string.IsNullOrEmpty(connString_) == true)
throw new ArgumentException("Invalid connection string");
**lock (this._sqlConn)**
{
this._sqlConn = new SqlConnection(connString_);
this._sqlConn.Open();
}
}
private void CloseConnection()
{
**lock (this._sqlConn)**
{
this._sqlConn.Close();
this._sqlConn.Dispose();
this._sqlConn = null;
}
}
}
您应该执行的步骤是: 不能保证线程安全 简单 每个线程都应该有自己的副本,并在数据库上进行锁定/同步 然后,它还将在计算机上扩展 这是过去20年左右的标准方法
因此,每个线程都会创建一个新的SqlWrapper,一切正常。数据库会为您执行连接池;尽可能地依靠它。你真的不应该要求锁定 备选案文1
- SqlConnection没有被DAO类封装;在方法级别,需要使用连接字符串的适当结构和存储
public class SomeDAO { private readonly string _connectionString; public SomeDAO(string dsn) { _connectionString = dsn; } public IEnumerable<AssetVO> DoWork() { const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]"; using (var conn = new SqlConnection(_connectionString)) { conn.Open(); using (var cmd = new SqlCommand(cmdText, conn)) using (var dr = cmd.ExecuteReader()) { while (dr.Read()) { yield return new AssetVO { AssetId = Guid.Parse(dr["AssetId"].ToString()), }; } } } } }
每个线程可能只有一个连接。然后,所有的线程安全问题都消失了。public class SomeDAO : IDisposable { #region backing store private readonly SqlConnection _connection; #endregion public SomeDAO(string dsn) { _connection = new SqlConnection(dsn); } public SqlConnection OpenConnection() { if (_connection.State != ConnectionState.Closed) _connection.Open(); return _connection; } public void CloseConnection() { if (_connection.State != ConnectionState.Closed) _connection.Close(); } public IEnumerable<AssetVO> DoWork() { const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]"; try { using (var cmd = new SqlCommand(cmdText, OpenConnection())) using (var dr = cmd.ExecuteReader()) { while (dr.Read()) { yield return new AssetVO { AssetId = Guid.Parse(dr["AssetId"].ToString()), }; } } } finally { CloseConnection(); } } #region Implementation of IDisposable /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> /// <filterpriority>2</filterpriority> public void Dispose() { _connection.Dispose(); } #endregion }
private static volatile bool _done; private static void Main() { #region keyboard interrupt ThreadPool.QueueUserWorkItem(delegate { while (!_done) { if (!Console.KeyAvailable) continue; switch (Console.ReadKey(true).Key) { case ConsoleKey.Escape: _done = true; break; } } }); #endregion #region start 3 threads in the pool ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback); ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback); ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback); #endregion Thread.Sleep(Timeout.Infinite); } private static void DatabaseWorkerCallback(object state) { Console.WriteLine("[{0}] Starting", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); while (!_done) { using (var dao = new SomeDAO(Properties.Settings.Default.DSN)) { foreach (var assetVo in dao.DoWork()) Console.WriteLine(assetVo); } } Console.WriteLine("[{0}] Stopping", Thread.CurrentThread.ManagedThreadId); }