使变量线程安全的最佳方法是什么?

时间:2012-08-13 14:51:49

标签: c# .net multithreading thread-safety

由于代码重构而出现了一个问题,在这种情况下,最佳解决方案是什么?

问题是DbConnection是从本地方法变量重构为类变量的。 该应用程序是多线程的。 似乎问题是DbConnection对象在成员变量时被共享。 什么是最好的解决方案?把它作为一种本地方法变得可变吗?

public IDataReader Execute(CommandBehavior behavior, string[] parameterNames, object[] arguments)
{

        DbConnection conn = null;
        try
        {

            conn = Connection.CreateConnection();

            DbCommand cmd = conn.CreateCommand();
            cmd.CommandText = StoredProcedureName;
            cmd.CommandType = CommandType.StoredProcedure;



           //     ..................................................

            // Perform the call.                        
            return DataCachingContext.SetCachedData(call, cmd.ExecuteReader(behavior));

        }
        catch (Exception ex)
        {
            //..........................
        }
        finally
        {
            //
        }

}

只是为了澄清,这是导致问题的版本。有了运行时异常,索引到ResultSets的问题,这很可能是由于连接被覆盖。

DbConnection _conn = null;

public IDataReader Execute(CommandBehavior behavior, string[] parameterNames, object[] arguments)
{

        try
        {

            _conn = Connection.CreateConnection();

            DbCommand cmd = _conn.CreateCommand();
            cmd.CommandText = StoredProcedureName;
            cmd.CommandType = CommandType.StoredProcedure;



           //     ..................................................

            // Perform the call.                        
            return DataCachingContext.SetCachedData(call, cmd.ExecuteReader(behavior));

        }
        catch (Exception ex)
        {
            //..........................
        }
        finally
        {
            //
        }

}

经过更多调查后,看起来DbConnection变量成为一个类变量来启用单元测试。当它是局部变量时,无法测试它的值。正在测试DbConnection的状态

5 个答案:

答案 0 :(得分:4)

我认为您正在寻找lock statement

  

lock确保一个线程不进入代码的关键部分,而另一个线程处于临界区。如果另一个线程试图输入一个锁定的代码,它将等待,阻止,直到该对象被释放。

答案 1 :(得分:1)

数据库连接对象通常应该是局部变量,因为数据库连接是一种相对昂贵的资源,可以在任何时间内保持打开状态。将数据库连接作为类变量的危险在于,在实例化对象时将打开连接,然后在处理类之前保持打开状态。这可能导致锁定未及时释放,以及长时间运行的事务,这会严重影响性能。

最好在需要之前打开连接(例如,调用存储过程,执行SQL语句),然后立即关闭/处理它。在封面下,数据库连接通常都会被缓存,这可以最大限度地减少重复打开和关闭连接的开销,因为当您在代码中打开连接时,您可能会从缓存中获得已打开的连接。

答案 2 :(得分:1)

  

该应用程序是多线程的。似乎问题是DbConnection对象在成员变量时被共享。什么是最好的解决方案?把它作为一种本地方法变得可变吗?

是的,使用DbConnection的一个好方法是在方法中创建和处理连接(将其存储在局部变量中)。在幕后,连接被汇集在一起​​,所以这样做没有明显的开销。您还可以避免处理共享状态和锁定。

问题中提供的代码完全符合我在此描述的内容。

答案 3 :(得分:1)

MSDN文档在DbConnection上说:

  

不保证所有实例成员都是线程安全的。

因此,在我看来,将它作为一个类变量并不是一个好主意。即使您的实现可能是线程安全的,但假设这样做也是冒险的。您可以使用锁来避免线程问题,但这些方法通常会导致严重的扩展。因此,最好将对象保持在本地。

如果您在打开和关闭太多连接的情况下担心性能,请查看SQL Server Connection Pooling (ADO.NET),它可以很好地汇集实际连接,而不是DbConnection个对象。< / p>

答案 4 :(得分:0)

在两个代码段中,您都可以创建新的Connection。那么将连接作为类变量的意图是什么?从您发布的代码中,看起来连接应该是局部变量。