VB.NET连接SQL Server启用MARS仍报连接已开错误如何解决?
问题根因(为什么启用MARS无效)
你遇到的报错和MARS的适用场景完全不匹配,启用MARS自然解决不了问题:
Cannot change property 'ConnectionString'. The current state of the connection is open
这个报错的本质是:你复用了全局的SqlConnection对象con,当它已经处于打开状态时,你的ConnServer()方法又尝试修改它的ConnectionString属性,这是被SQL Server连接类禁止的操作。MARS的作用是支持同一个打开的连接上同时存在多个活跃的DataReader结果集,完全不解决你当前的场景问题。
你的代码里还有几个直接导致报错的逻辑问题:
getemail方法里Return strMailTo之后的sqLdr.Close()、closeCon()代码永远不会执行,导致全局连接一直处于打开状态- 你在循环里每次调用
getattachment都会再次执行ConnServer(),此时全局连接已经打开,修改ConnectionString直接触发报错 getemail里已经用SqlDataAdapter.Fill把数据加载到了DataTable,多余执行了一次cmd.ExecuteReader(),完全没有必要- 拼接SQL字符串存在SQL注入风险,属于额外的安全隐患
修复方案
核心原则
不要复用全局SqlConnection对象,.NET自带数据库连接池会自动管理连接的创建销毁,每次操作数据库时新建连接、用完自动释放即可。
所有实现了IDisposable接口的数据库操作对象(SqlConnection、SqlCommand、SqlDataAdapter、SqlDataReader)都用Using语句包裹,不需要手动调用Close/Dispose。
修正后的代码示例
可以完全弃用原来的ConnServer()和closeCon()全局连接管理方法,直接从配置读连接字符串每次新建连接:
' 先引入命名空间 Imports System.Data.SqlClient Imports System.Configuration Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim obj As String = TextBox1.Text Dim body As String = TextBox2.Text For Each mail In getemail() Send_mail(mail, obj, body, getattachment(mail)) Next MsgBox("Traitement effectué") End Sub Function getemail() As List(Of String) Dim strMailTo As New List(Of String) Dim SQL As String = "Select EMail FROM [USER] WHERE EMail Is Not NULL And MatriculeSalarie Is Not NULL And [EMail] <> '' and EtatPaie = 3 and BulletinDematerialise = 1 " ' 每次新建连接,用Using自动释放 Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("ConString").ConnectionString) Using cmd As New SqlCommand(SQL, con) con.Open() Using sda As New SqlDataAdapter(cmd) Using ds As New DataTable() sda.Fill(ds) ' 不需要多余的ExecuteReader,直接遍历DataTable就行 For Each dr As DataRow In ds.Rows strMailTo.Add(dr("EMail").ToString()) Next End Using End Using End Using End Using Return strMailTo End Function Function getattachment(email As String) As String() ' 参数化查询,避免SQL注入 Dim SQL As String = "Select MatriculeSalarie FROM [USER] WHERE [EMail]=@Email" Dim mat As String = "" Dim Dir As String = ConfigurationManager.AppSettings("path1").ToString() Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("ConString").ConnectionString) Using cmd As New SqlCommand(SQL, con) ' 添加参数 cmd.Parameters.AddWithValue("@Email", email) con.Open() Using sqLdr As SqlDataReader = cmd.ExecuteReader() While sqLdr.Read mat = sqLdr.GetValue(sqLdr.GetOrdinal("MatriculeSalarie")).ToString() End While End Using End Using End Using Return IO.Directory.GetFiles(Dir, mat.Substring(1) & "*.pdf") End Function
内容的提问来源于stack exchange,提问作者user9067306
相关产品推荐
相关产品推荐

