2012-08-13 109 views
0

由于代码重构而出现问题,在这种情况下最好的解决方案是什么?制作可变线程安全的最佳方式是什么?

问题是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 
     { 
      // 
     } 

} 

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

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的状态正在测试中

+4

最好的方法是研究[标签:线程安全]和[标签:多线程]。这个问题在这里被问了数百次;可能已经被问过_today_。 – 2012-08-13 14:53:42

+1

我在这里没有看到任何问题,除了你说DbConnection是一个类变量,在这里它显然是一个局部变量,你有两次声明吗?如果这不是问题,我们需要更多细节。 – crlanglois 2012-08-13 14:55:56

+0

我在代码中看不到任何线程。 DataCachingContext是共享对象吗?它是“静态”吗? – 2012-08-13 14:59:08

回答

1

该应用程序是多线程的。看来问题在于当它是一个成员变量时,DbConnection对象被共享。什么是最好的解决方案?把它当作本地方法变得可变?

是的,使用DbConnection的良好模式是在方法中创建和配置连接(将其存储在本地变量中)。在幕后,连接被汇集起来,所以没有像这样做的重大开销。您还可以避免必须处理共享状态和锁定。

问题中提供的代码与我在这里描述的完全一致。

+0

经过更多的调查后,它看起来像DbConnection变量是一个类变量,以启用单元测试。当它是一个局部变量时,没有办法测试它的价值。 DbConnection的状态正在测试中。 – learnerplates 2012-08-13 15:41:45

+0

其实你可以实现并传递'DbProviderFactory'到你的类为了产生单元测试的模拟连接:http://msdn.microsoft.com/en-us/library/ms971499.aspx – 2012-08-13 15:54:18

+0

木渎,我不了解这个。你可以解释吗?现在我正在寻找类变量的替代方案,以便我可以从单元测试中测试DbConnection的状态。有一些方法可以从一些全球存储获得连接吗?然后测试它的状态。 – learnerplates 2012-08-14 12:03:17

4

我认为您正在寻找lock statement

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

+0

只要确保处理好您的异常以避免不释放该对象。 – 2012-08-13 14:59:54

+4

@Andre不需要。使用'lock'自动处理 - 实际上,这就是使用'lock'而不是'Monitor.Enter'的全部要点。 – 2012-08-13 15:01:27

+0

@KonradRudolph如果'using'块内发生异常,对象是否仍然被释放? – 2012-08-13 16:51:40

1

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

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

1

MSDN文档上说DbConnection

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

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

如果你担心的情况下,过多的连接打开和关闭所有的时间表现,看看SQL Server Connection Pooling (ADO.NET)这确实相当不错池实际连接,而不是DbConnection对象。

0

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

相关问题