C#Winform窗体应用程序中查询数据库时报错问题分析
				
									
					
					
						|  | 
							admin 2025年1月19日 14:42
								本文热度 1658 | 
					
				 
				执行长时间任务查询数据库,那么可能会出现一个问题:在执行长时间任务的过程中,如果点击了进度条中的“取消”按钮,此时可以停止程序执行查询数据库的任务,但是如果再次执行该任务时,可能会报错:“连接未关闭,连接的当前状态为打开”。下面以一个简单的示例来看看出现上面所述问题的原因所在。首先,用access创建一个数据库文件database.mdb,并保存在C#项目的bin\debug文件夹中。创建一个数据表TestData,在数据表里设置一个自增字段、一个姓名字段,一个年龄字段。仍然使用上一篇文章中所创建窗体和类,只把DataOperate.cs这个类修改一下,改成以下的代码,用于模拟耗时的数据库读取任务:using System;
using System.ComponentModel;
using System.Data.OleDb;
using System.Data;
using System.IO;
using System.Threading;
namespace Test
{
    internal class DataOperate
    {
        private static String StrConn;
        private static OleDbConnection conn;
        private static OleDbCommand sc;
        public void operating(BackgroundWorker worker)
        {
            ConnectDatabase();
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(1000);  //暂停1秒,模拟耗时的数据库操作
                operate("insert into TestData(姓名,年龄) values('全栈开发的码农',3)");
                worker.ReportProgress(i*100/10);
            }
        }
       
        private void ConnectDatabase()
        {
            //连接数据库
            StrConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Directory.GetCurrentDirectory() + @"\database.mdb; " + "Persist Security Info=True;Jet OLEDB:Database Password=123456";
            try
            {
                conn = new OleDbConnection(StrConn);
            }
            catch (System.Data.SqlClient.SqlException ex)
            {
                throw new Exception(ex.Message);
            }
        }
        private void operate(String strsql)//插入、删除、更新等数据库操作
        {
            conn.Open();
            sc = new OleDbCommand();
            sc.CommandText = strsql;
            sc.Connection = conn;
            Thread.Sleep(1000);  //暂停1秒,模拟耗时的数据库操作
            sc.ExecuteNonQuery();
            conn.Close();
        }
        public void close()  //关闭数据库连接
        {
            if (conn.State == ConnectionState.Open)
            {
                conn.Close();
                conn.Dispose();
            }
        }
    }
}
此时,点击主窗体中的“开始”按钮,开始执行任务,往数据库里的TestData数据表插入记录,程序运行正常。执行到一半的时候,点击进度条窗体中的“取消”按钮,此时任务被取消。此时,如果再次点击主窗体中的“开始”按钮,出现“连接未关闭”的报错。经分析,问题出现在OleDbConnection对象conn上,在DataOperate.cs类中,把OleDbConnection对象conn定义成static静态对象,这对于一般的数据库操作是没有问题的,因为每一个数据库执行方法中都有conn.open()和conn.close(),数据连接可以正常打开和正常关闭,而当使用了Backgroundworker对象进行进度报告时,中途突然中断数据库查询操作,那么会导致conn.close()无法正常执行,使得连接依然处于打开状态,下一次尝试再次连接时就出现了“连接未关闭”的报错。解决问题的最简单粗暴的方法就是把static删除,使conn成为一个普通的非静态变量即可。这是因为static对象在程序运行的全过程中只能有一个实例,第一次执行数据库操作时,它已经实例化,再次执行数据库操作时,也只能使用它,不能再次实例化,而它没有被正常关闭连接,所以再次尝试连接数据库时会出现“连接未关闭”的情况,而如果采用了非静态变量,那么就相当于给conn对象重新实例化,用一个全新的完全不同于此前的实例来操作数据库,这样就不会报错了。
阅读原文:原文链接
该文章在 2025/1/21 9:36:19 编辑过