在 DAL class ThreadLocal 中创建 SqlConnection 是否安全?

Is it safe to make SqlConnection in a DAL class ThreadLocal?

我有以下 DAL class 层次结构(部分显示),我用它来抽象化对数据库的数据访问。我想以线程安全的方式使用它:

public class DbAdapter : IDbAdapter, IDisposable
{
    private SqlConnection _conn;
    private readonly string _connString;

    protected DbAdapter(string connString)
    {
        if (string.IsNullOrWhiteSpace(connString))
            throw new ArgumentException("Value cannot be null, empty or whitespace", nameof(connString));
        _connString = connString;
    }

    public void Dispose()
    {
        CloseConnection();
    }

    public SqlConnection GetConnection()
    {

        if (_conn == null || _conn.State == ConnectionState.Closed)
            _conn = new SqlConnection(_connString);
        else if (_conn.State == ConnectionState.Broken)
        {
            _conn.Close();
            _conn.Open();
        }
        return _conn;
    }

    public void CloseConnection()
    {
        if (_conn != null && _conn.State == ConnectionState.Open)
            _conn.Close();
        _conn = null;
    }

    public SqlCommand GetCommand(string query, SqlTransaction transaction)
    {
        var cmd = new SqlCommand
        {
            Connection = transaction != null ? transaction.Connection : GetConnection()
        };
        if (transaction != null)
            cmd.Transaction = transaction;
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = query;
        cmd.CommandTimeout = 500;
        return cmd;
    }
    
    // Omitted other methods
}

public class PersonDba : DbAdapter 
{
    //Omitted 

    public IList<Person> GetPersons(string whereClause, string orderClause, SqlTransaction transaction = null)
    {
        var query = "SELECT Id, Name, PersonId, Birthdate, Modified FROM Persons ";

        if (!string.IsNullOrWhiteSpace(whereClause))
            query += whereClause;
        if (!string.IsNullOrWhiteSpace(orderClause))
            query += orderClause;

        IList<Person> result = new List<Person>();

        var sqlCmd = GetCommand(query, transaction);
        using (var reader = sqlCmd.ExecuteReader(CommandBehavior.CloseConnection))
        {
            while (reader.Read())
            {
                var person = new Person
                {
                    Id = reader.GetInt32(reader.GetOrdinal("Id")),
                    PersonId = reader.GetInt32(reader.GetOrdinal("PersonId")),
                    Name = reader.GetString(reader.GetOrdinal("Name")),
                    Birthdate = reader.GetDateTime(reader.GetOrdinal("Birthdate")),
                    LastModified = reader.GetDateTime(reader.GetOrdinal("Modified"))
                };
                result.Add(person);
            }
        }
        return result;
    }
}

通常,我将 PersonDba 的单个实例注入其他 classes,其中包含多线程代码。为了避免在相关代码中锁定对单个实例的所有访问,我正在考虑制作 ThreadLocal<SqlConnection> 类型的 SQLConnection DbAdapter._conn(请参阅 ThreadLocal)。这足以确保使用此 class 的实例是线程安全的吗?

假设您希望在未来通过使用 ExecuteReaderAsync 而不是 ExecuteReader 来保持使您的 DAL 异步的可能性,然后转换 _conn 的字段class DbAdapterThreadLocal<SqlConnection> 不安全。原因是在等待异步请求之后,异步工作流很可能会在另一个 ThreadPool 线程上继续。所以错误的连接将被关闭,一些其他不相关的并发数据访问操作可能会被中断并中止。