首页 新闻 会员 周边

已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭。

0
悬赏园豆:120 [已解决问题] 解决于 2015-07-19 18:13

先上代码:

数据库访问核心代码

 1 try
 2             {
 3                 //_dbConnection是全局的实例属性DbConnection,在构造中初始化了
 4                 //注意:此处使用全局的实例属性DbConnection,就会出现标题的异常
 5                 var cmd = _dbConnection.CreateCommand();
 6                 cmd.CommandText = sql;
 7                 cmd.CommandType = System.Data.CommandType.Text;
 8                 if (dbParameterCollection != null)
 9                     foreach (var item in dbParameterCollection)
10                     {
11                         cmd.Parameters.Add(item);
12                     }
13                 if (_dbTrans != null)
14                     cmd.Transaction = _dbTrans;
15                 if (_dbConnection != null && _dbConnection.State != System.Data.ConnectionState.Open)
16                 {
17                     _dbConnection.Open();
18                 }
19                 return cmd.ExecuteReader();
20             }
21             catch (Exception ex)
22             {
23                 throw;
24             }

测试代码:

 1             var arr = Enumerable.Range(0, 49).ToArray();
 2             using (var db = new DBHelper())
 3             {
 4                 //using (var tran = new Trans(db))
 5                 //{
 6                     try
 7                     {
 8                         Parallel.For(0, 49, (i) =>
 9                         {
10                             var item = arr[i];
11                             Console.WriteLine("开始执行:{0}", item);
12                             //3.得到此设备下所有点信息
13                             var tagInfo = db.Query<Books>(string.Format("select * from books where id='{0}'", Guid.NewGuid()));
14                         });
15                     }
16                     catch (Exception ex) { }
17                 //}
18             }
19             Console.WriteLine("123");
20 
21             Console.ReadLine();

Query方法:

 1         public IEnumerable<T> Query<T>(string sql, IEnumerable<DbParameter> dbParameterCollection = null) where T : class,new()
 2         {
 3             var reader = ExecDataReader(sql, dbParameterCollection);
 4 
 5             try
 6             {
 7                 var ls = new List<T>();
 8 
 9                 return ls;
10             }
11             catch (Exception ex)
12             {
13 
14                 throw new Exception("DataReader映射为实体时出错!", ex);
15             }
16             finally
17             {
18                 tools.CloseIDataReader(reader);
19             }
20         }

问题:

将全局的DbConnection每次都重新实例化就不会报标题的异常了,但是事务无法使用,

请问,怎么完美解决此问题,可以使用事务!!!

问题补充:

_dbConnection是类的实例属性,不是静态属性

我的用户名的主页 我的用户名 | 初学一级 | 园豆:43
提问于:2015-07-19 16:20
< >
分享
最佳答案
0

这代码问题太多了。

首先,不要在并行代码里复用DbConnection,改为一次数据库操作using一个DbConnection即可。

其次,DbConnection和DataReader之类的对象建议使用using简洁语法,显式Close或者Dispose也可以,但是多线程环境下你必须保证每个线程操作的数据对象上下文是隔离的,否则显式Close或者Dispose都可能抛出异常。

最后,DBHelper抽象后使用有问题,你的DBHelper只是对象ado.net进行了简易封装,可能是为了调用方便,它显然不能保证线程安全,using一个DBHelper后,进行并行操作显然和DBHelper封装的初衷是不相符的。

PS:查询还是少用显式事务,除非你的业务要求非常特殊。

收获园豆:70
JeffWong | 老鸟四级 |园豆:2328 | 2015-07-19 16:46

 恩,并行里复用DbConnection会有此问题。
我在DbConnection和DataReader使用完毕后都有显示Close
多线程下,怎么保证DbConnection和DataReader上下文隔离,是我想要达到的目的
至于DBHelper没有保证线程安全,我尽量保证了,没有使用静态属性或字段传递。
水平有限,不知道那些需要注意线程安全,是否需要查询CSDN看DbConnection和DataReader等Ado.NET对象是否线程安全?还望赐教

我的用户名 | 园豆:43 (初学一级) | 2015-07-19 16:53
其他回答(2)
0

事务无法使用和connection有什么关系.connection每次用完就要dispose的...

我觉得吧,看你写的代码,我觉得要不你交给dapper.你说的这些都支持.

收获园豆:20
Cherbim | 园豆:323 (菜鸟二级) | 2015-07-19 16:33

事务要关联到对应连接,如果连接关闭,事务也就丢失了

支持(0) 反对(0) 我的用户名 | 园豆:43 (初学一级) | 2015-07-19 16:38
0

就是让你,在写reader没有关闭的代码里面,不要再使用查询或者其它操作,因为你可能是用的SQlHelper所以会有这样的问题,你可以在一个事务中分部取值不要嵌套查询(Reader)和执行代码(NonQuery)代码。

收获园豆:30
Supper_litt | 园豆:827 (小虾三级) | 2015-07-19 17:18

我想创建一个事务类保存多次创建执行的dbconnection,然后一起提交就可以了。

支持(0) 反对(0) 我的用户名 | 园豆:43 (初学一级) | 2015-07-19 18:09
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册