C# 执行DB访问的后台线程挂起UI
我制作了一个小的实用程序来测试电脑是否可以连接到某个Oracle数据库 为了保持UI的响应性,并查看进度步骤,我将DB代码放在后台线程中。令我惊讶的是,UI仍然挂起(但没有那么多) 这个应用程序真的没什么大不了的,但我认为这个案例总的来说很有趣,线程中的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
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
{
}
}
}