当执行某些需要花费很长时间才能完成的数据库操作时,往往需要设置设计异步的处理的方法,以避免用户长期得不到响应,导致程序假死。在ADO.Net 2.0中,其SqlCommand类也提供了一组Begin~和End~的Execute方法对,用于执行异步操作,通过这些方法对,用户可以轻松地实现异步操作,而不需要掌握过多的线程开发技术细节。比如ExecuteNonQuery 相应的异步方法为 BeginExecuteNonQuery,EndExecuteNonQuery。
同步与异步方法在调用上的差异在于:同步方法执行后,会阻塞处理进程,直接返回处理结果,而异步执行方法通过Begin~方法启动执行处理,然后将处理权交给调用者,调用者可以做别的事情,如果要取得异步执行的结果,需要调用End~方法,否则结果会丢失。
在异步执行处理中,主要需要考虑的是在异步执行开始后(通过Begin~方法的调用),如果获取异步执行的状态,以便在需要的时候,通过End~方法取回异步执行的结果。每个IAsyncResult接口对象,如果需要知道Begin~方法执行的状态,可以查询IAsyncResult接口对象的IsCompleted属性。当该属性返回True时,表示异步方法执行完成,可以调用与之对应的End~方法获取执行结果。 如果在异步执行完成前调用~End方法,则~End方法会等待,阻塞主线程,直到异步方法执行完成并返回结果。比较常用的另一种方法是:在调用Begin~方法开始异步执行时,传入委托实例。Begin~有几个重载,其中有2个可以传入委托实例,由执行异步方法的工作线程通过委托自动回调制定的回调函数。下面这个例子说明了这种方法。
如图建立Windows程序,下方是一TabPage控件。代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace queryCallBackDemo
{
public partial class Form1 : Form
{
private Int32 m_runningCount = 0;
private string m_ConnStr = "Data Source=xiaoxiao\\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=True;Asynchronous Processing=true";
private SqlConnection getConnection()
{
SqlConnection iRe = new SqlConnection(this.m_ConnStr);
iRe.Open();
return iRe;
}
private delegate void addNewTabPageDelegate(TabPage sTabPage);
private void addNewTabPage(TabPage sTabPage)
{
this.tabControl1.TabPages.Add(sTabPage);
}
private void handleCallBack(IAsyncResult iResult)
{
try
{
using (SqlCommand iCmd = iResult.AsyncState as SqlCommand)
{
TabPage iTabPage = new TabPage(iCmd.CommandText);
DataGridView iDataGridView = new DataGridView();
iDataGridView.Parent = iTabPage;
iDataGridView.Dock = DockStyle.Fill;
using (DataTable iDatatable = new DataTable())
{
iDatatable.Load(iCmd.EndExecuteReader(iResult));
iDataGridView.DataSource = iDatatable;
}
this.Invoke(new addNewTabPageDelegate(this.addNewTabPage), iTabPage);
// this.tabControl1.TabPages.Add(iTabPage);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.m_runningCount -= 1;
}
}
private void asyncExecuteQuery(string sSQL)
{
SqlCommand iCmd;
try
{
iCmd = new SqlCommand(sSQL, getConnection());
iCmd.BeginExecuteReader(new AsyncCallback(this.handleCallBack), iCmd);
this.m_runningCount += 1;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.m_runningCount > 0)
{
MessageBox.Show(m_runningCount.ToString() + " query are still running, please wait");
e.Cancel = true;
}
}
private void btnDoquery_Click(object sender, EventArgs e)
{
string iSQL = this.textBox1.Text.Trim();
if (!string.IsNullOrEmpty(iSQL))
this.asyncExecuteQuery(iSQL);
}
private void btnClear_Click(object sender, EventArgs e)
{
if (this.m_runningCount > 0)
MessageBox.Show(m_runningCount.ToString() + " query are still running, please wait");
else
this.tabControl1.TabPages.Clear();
}
}
}
几个注意:连接串加上 Asynchronous Processing=true 。
iCmd.BeginExecuteReader(new AsyncCallback(this.handleCallBack), iCmd); 开始异步委托调用,
SqlCommand iCmd = iResult.AsyncState as SqlCommand 获取传入的ICmd
异步调用中不能直接 this.tabControl1.TabPages.Add(iTabPage);
因为tabControl1.是在另一个线程中创建的,而要使用 this.Invoke(new addNewTabPageDelegate(this.addNewTabPage), iTabPage);