嘗試使用異步/等待和事務將多個記錄插入MySQL數據庫,但是它仍然會導致UI在循環中變爲凍結/無響應。使用事務進行批量插入會阻止異步進程上的UI
看下面的代碼,我在做什麼錯誤或如何實現,以便在此過程中UI仍然響應。
的異步方法
public static async Task AddRecords() {
foreach (string month in Months) {
await MakeTable(month);
string query="INSERT INTO `"+month+"` (Caller, Started, Dialed, DurationSec, DurationMin, Cost, Location, Switch) VALUES (@Caller, @Started, @Dialed, @DurationSec, @DurationMin, @Cost, @Location, @Switch);";
using (MySqlConnection cn=new MySqlConnection(ConnectionString.ToString())) {
await cn.OpenAsync();
using (MySqlTransaction trans=cn.BeginTransaction()) {
using (MySqlCommand cmd=new MySqlCommand(query, cn, trans)) {
cmd.CommandType=CommandType.Text;
foreach (Record r in CDR.Records) {
if (r.Started.ToString("yyyy-MM")==month) {
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Caller", r.Caller);
cmd.Parameters.AddWithValue("@Started", r.Started);
cmd.Parameters.AddWithValue("@Dialed", r.Dialed);
cmd.Parameters.AddWithValue("@DurationSec", r.Duration);
cmd.Parameters.AddWithValue("@DurationMin", Math.Ceiling(r.Duration/60));
cmd.Parameters.AddWithValue("@Cost", r.Cost);
cmd.Parameters.AddWithValue("@Location", r.Location);
cmd.Parameters.AddWithValue("@Switch", r.Switch.ToString());
cmd.ExecuteNonQuery();
}
}
trans.Commit();
}
}
await cn.CloseAsync();
}
}
}
上這是如何被稱爲一個片段:
private async void button1_Click(object sender, EventArgs e) {
this.Text = "Adding Records";
await AddRecords();
this.Text = "Completed";
}
順便說一句,該當UI阻塞,不應該它塊畢竟之前的代碼已經被執行。例如,在上面的按鈕點擊方法中,第一個'this.Text'沒有設置,因爲一旦await AddRecords();
執行,它就發生在UI有機會完成更新之前,並且直到阻塞完成之後纔會完成這導致在UI級別僅注意到this.Text - "Completed"
。
UPDATE
的UI修改cmd.ExecuteNonQuery();
到await cmd.ExecuteNonQueryAsync();
(由Yuval Itzchakov推薦),這使我相信它阻止在trans.Commit();
線或某事與交易是怎麼做的後,仍然阻擋正在建設。
更新代碼
public static async Task AddRecords() {
foreach (string month in Months) {
await MakeTable(month);
string query="INSERT INTO `"+month+"` (Caller, Started, Dialed, DurationSec, DurationMin, Cost, Location, Switch) VALUES (@Caller, @Started, @Dialed, @DurationSec, @DurationMin, @Cost, @Location, @Switch);";
using (MySqlConnection cn=new MySqlConnection(ConnectionString.ToString())) {
await cn.OpenAsync();
using (MySqlTransaction trans=cn.BeginTransaction()) {
using (MySqlCommand cmd=new MySqlCommand(query, cn, trans)) {
cmd.CommandType=CommandType.Text;
foreach (Record r in CDR.Records) {
if (r.Started.ToString("yyyy-MM")==month) {
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Caller", r.Caller);
cmd.Parameters.AddWithValue("@Started", r.Started);
cmd.Parameters.AddWithValue("@Dialed", r.Dialed);
cmd.Parameters.AddWithValue("@DurationSec", r.Duration);
cmd.Parameters.AddWithValue("@DurationMin", Math.Ceiling(r.Duration/60));
cmd.Parameters.AddWithValue("@Cost", r.Cost);
cmd.Parameters.AddWithValue("@Location", r.Location);
cmd.Parameters.AddWithValue("@Switch", r.Switch.ToString());
await cmd.ExecuteNonQueryAsync();
}
}
trans.Commit();
}
}
await cn.CloseAsync();
}
}
}
謝謝Nitram。我正在考慮以這種方式實施,但是要確保沒有辦法做。提交而不會阻止用戶界面。我確實注意到Commit有一個上下文,但它看起來(不確定)只是關於如何鎖定表或記錄。 –
你的語法也有輕微的改正。而不是'等待Task.Run(AddRecords);'它應該'等待Task.Run(()=> AddRecords());'如果你想更新你的帖子。 –
@SanuelJackson我通常使用VB.net,對不起。但我實際上並不打算在那裏創建一個lambda函數,而是引用一個委託函數。這不就是這樣嗎?關於一般答案:您有什麼擔憂? 'AddRecords'函數將像以前一樣工作,其優點是'await'不會同步到UI,但可以在'ThreadPool'中安排延續。 – Nitram