C# 执行DB访问的后台线程挂起UI

C# 执行DB访问的后台线程挂起UI,c#,database,multithreading,oracle,user-interface,C#,Database,Multithreading,Oracle,User Interface,我制作了一个小的实用程序来测试电脑是否可以连接到某个Oracle数据库 为了保持UI的响应性,并查看进度步骤,我将DB代码放在后台线程中。令我惊讶的是,UI仍然挂起(但没有那么多) 这个应用程序真的没什么大不了的,但我认为这个案例总的来说很有趣,线程中的DB代码挂起了UI线程 private void bgwDataAccess_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker bgw = se

我制作了一个小的实用程序来测试电脑是否可以连接到某个Oracle数据库

为了保持UI的响应性,并查看进度步骤,我将DB代码放在后台线程中。令我惊讶的是,UI仍然挂起(但没有那么多)

这个应用程序真的没什么大不了的,但我认为这个案例总的来说很有趣,线程中的DB代码挂起了UI线程

    private void bgwDataAccess_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bgw = sender as BackgroundWorker;

        try
        {
            bgw.ReportProgress(0, "Starting...\r\n");
            bgw.ReportProgress(0, "Active ConnectionString:\r\n");
            bgw.ReportProgress(0, Settings.Default.ConnctionString + "\r\n\r\n");

            OracleConnection con = new OracleConnection(Settings.Default.ConnctionString);
            OracleCommand cmd = new OracleCommand("SELECT Count(*) FROM MYTABLE", con);


            bgw.ReportProgress(0, "Opening db...\r\n");
            con.Open();
            bgw.ReportProgress(0, "Opened.\r\n\r\n");

            bgw.ReportProgress(0, "Executing SQL-query...\r\n");
            Object result = cmd.ExecuteScalar();
            bgw.ReportProgress(0, String.Format("Result: {0}\r\n\r\n", result.ToString()));

            con.Close();
        }
        catch (Exception)
        {
            throw;
        }
    }

    private void bgwDataAccess_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        txtResult.Text += e.UserState;           
    }

在此之前,您是否在代码中的任何位置访问Oracle命名空间?这只是一个猜测,但可能暂停是您的应用程序加载所需的.dll

您可以尝试预加载模块。我在我的应用程序中使用类似下面的代码。首先,我显示一个启动屏幕,显示应用正在加载,然后调用下面的代码段加载所有必需的DLL。这样,一旦应用程序被加载,就不会有任何停顿

void PreloadDLLs()
{
    Assembly^ assembly = Assembly::GetEntryAssembly();
    array<System::Reflection::AssemblyName^>^ referencedAssemblies = assembly->GetReferencedAssemblies();
    for each(System::Reflection::AssemblyName^ referencedAssemblyName in referencedAssemblies)
    {
        try
        {
            Assembly^ a = assembly->Load(referencedAssemblyName);
        }
        catch(System::Exception^ /*e*/)
        {

        }
    }
}
您可以将查询更改为“从MYTABLE中选择前1个id”,其影响将相同


如果影响不是由这些操作造成的,您可以使用探查器找出哪些.net代码会造成影响。

请注意,如果这不能解决您的问题,请删除捕获,然后在finally中使用try finally关闭连接。您应该在try块之前声明(但不打开)连接,以便在finally中也可以使用con对象。是的,您完全正确!你能定义/描述“挂起UI线程”吗?这有多严重?为什么要使用BackgroundWorker bgw=发件人作为BackgroundWorker;和bgw.ReportProgress(0,“开始…\r\n”);?您可以直接调用bgwDataAccess.ReportProgress()对吗?也可以使用Using()而不是明确地关闭/处理连接您是否确定BackgroundWorker已设置为支持报告进度(WorkerReportsProgress)?谢谢您的回答。我试过了,但这次没什么不同。虽然你的建议是一个很好的技巧,在将来可能会有用。
using System;
using System.Reflection;

private void PreloadDLLs()
{
    Assembly assembly = Assembly.GetEntryAssembly();
    System.Reflection.AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies();
    foreach(System.Reflection.AssemblyName referencedAssemblyName in referencedAssemblies)
    {
        try
        {
            Assembly a = assembly.Load(referencedAssemblyName);
        }
        catch
        {

        }
    }
}