我在使用async / await时遇到使用事务范围回滚的问题。一切都在没有事务范围的情况下工作,但每当我故意引起异常(第二次迭代的插入上的重复主键)时,就不会发生回滚(用于更新)或任何类型的与事务相关的错误。
下面按钮事件处理程序中的代码只是测试事务范围的示例。主要目标是能够异步更新事务中包含的循环中的多个表,因此我可以避免UI死锁并对循环期间可能发生的任何异常执行回滚。我的问题的任何替代或建议表示赞赏,谢谢:)
private async void button1_Click(object sender, EventArgs e)
{
try
{
int customerCount = 150; // First 150 rows of customer table
TransactionScope transaction = null;
using (OleDbConnection dbConn = new OleDbConnection(Provider = Microsoft.ACE.OLEDB.12.0; OLE DB Services=-4; Data Source = " + filePath))
{
dbConn.Open();
using (transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
for (int i = 0; i < customerCount; i++)
{
// Update field indicating customer made an invoice
var taskName = sql.executeAsync("UPDATE Customer SET lastInvoiceDate = @date WHERE customerID = @custID", dbConn,
new OleDbParameter("@date", DateTime.Today),
new OleDbParameter("@custID", i));
// Insert new invoice - Breaks here
var taskInsert = sql.executeAsync("INSERT INTO Invoice VALUES (1, 'thisisatestinvoice', '$100.50')", dbConn);
await Task.WhenAll(taskName, taskInsert);
}
}
// All updates executed properly
transaction.Complete();
}
}
catch (AggregateException exception)
{
foreach (Exception ex in exception.InnerExceptions)
{
MessageBox.Show(ex.Message);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public async Task executeAsync(string dbQuery, OleDbConnection dbConn, params OleDbParameter[] parameters)
{
var dbComm = new OleDbCommand(dbQuery, dbConn);
if (parameters != null)
dbComm.Parameters.AddRange(parameters);
await dbComm.ExecuteNonQueryAsync().ConfigureAwait(false);
}
答案 0 :(得分:0)
我无法让交易范围发挥作用,而且我不完全确定问题是什么,我认为这是因为我在ACE.OLEDB.12.0上,但是我找到了OleDbTransaction的另一个替代方案,如果发生任何故障,它将回滚。
private async void button1_Click(object sender, EventArgs e)
{
try
{
using (OleDbConnection dbConn = new OleDbConnection(SQLWrapper.CONNECT_STRING))
{
dbConn.Open();
OleDbTransaction dbTrans = dbConn.BeginTransaction();
var taskName = sql.executeAsync("UPDATE Config SET Busname = @name", dbConn, dbTrans,
new OleDbParameter("@name", "name"));
var taskInsert = sql.executeAsync("INSERT INTO Callout VALUES (16, 'ryanistesting')", dbConn, dbTrans);
await Task.WhenAll(taskName, taskInsert);
dbTrans.Commit();
}
}
}
public async Task executeAsync(string dbQuery, OleDbConnection dbConn, OleDbTransaction dbTrans, params OleDbParameter[] parameters)
{
using (var dbComm = new OleDbCommand(dbQuery, dbConn))
{
if (parameters != null)
dbComm.Parameters.AddRange(parameters);
if (dbTrans != null)
dbComm.Transaction = dbTrans;
await dbComm.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
答案 1 :(得分:0)
也许您已经知道答案了一段时间了。我也遇到了同样的问题。事实是,当使用ConfigureAwait(false)时,您是在告诉运行时从线程池中选择任何空闲线程,而不是等待调用async方法时等待先前使用的线程。在不同的上下文中使用不同的线程,从而在同一事务范围内创建仅用于一个连接的另一个连接。然后,该事务被提升为分布式事务。那是我的经验,我不得不放弃最好使用async的想法,并通过不使用configureAwait(false)或Task.WhenAll来等待previos线程完成。希望对您有所帮助!