VB.NET操作Access报已打开关联DataReader需先关闭错误求解
问题根因
你触发的There is already an open DataReader associated with this Command which must be closed first.错误,本质是Access使用的Jet OLEDB提供程序不支持同连接多活动结果集特性:单个数据库连接上只要存在未关闭的DataReader,就无法在关联的Command对象上发起新的查询。
你的代码存在4个直接触发错误或潜在隐患的问题:
- 第一次调用
cmd.ExecuteReader()生成DataReader实例后,没有关闭该Reader就执行后续操作,第二次调用cmd.ExecuteReader()时旧Reader仍占用连接,直接触发报错 - 同时创建了两套指向同一个mdb文件的连接:ADO.NET体系的
OleDbConnection对象con、COM互操作的ADODB.Connection对象conn,属于完全冗余的写法,极易引发文件锁、连接占用冲突 - 拿到DataReader后没有调用
Read()方法将游标移动到第一行有效数据,直接调用GetString()取值,即使解决DataReader冲突也会触发"无当前数据行"异常 - 所有数据库对象(连接、命令、读取器)都没有做确定性资源释放,代码多次运行后会出现连接池占满、mdb文件被锁定无法访问的问题
修正代码
删除冗余的ADODB连接相关逻辑,全程使用ADO.NET标准写法操作Access,通过Using块自动释放资源,严格遵守DataReader打开/关闭顺序:
' 移除所有未使用的冗余声明、ADODB.Connection相关的所有逻辑 Dim sql As String = "SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'" Dim sh1 As String = "" xlWorkSheet1.Columns(5).Insert sh1 = LTrim$(xlWorkSheet1.Cells(i, 1).Text) ' Using块会在代码执行结束后自动关闭、释放数据库连接 Using con As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + openExcel + "\Test.mdb;Persist Security Info=False") con.Open() ' Using块包裹Command对象,自动释放资源 Using cmd As New OleDbCommand(sql, con) ' Using块包裹DataReader,退出代码块时自动关闭读取器 Using myReader As OleDbDataReader = cmd.ExecuteReader() ' 先判断是否查询到匹配数据,移动游标到有效行再取值 If myReader.Read() Then xlWorkSheet1.Cells(1, 5) = myReader.GetString(0) xlWorkSheet1.Cells(1, 11) = myReader.GetString(1) End If End Using End Using End Using
注意事项
- 如果你的查询可能返回多行结果,需要在
myReader.Read()外层加Do While循环遍历所有行,上述示例默认取查询结果的第一行匹配数据 - 如果确实需要在遍历DataReader的过程中执行其他数据库操作,必须新开一个独立的数据库连接,不能复用DataReader占用的连接
- 不要混用ADODB COM对象和ADO.NET原生对象操作同一个Access文件,两类对象的连接池是独立的,非常容易出现锁冲突
内容的提问来源于stack exchange,提问作者Lucas Ke
相关产品推荐
相关产品推荐

