事务范围不使用async / await回滚

时间:2018-02-21 22:54:47

标签: c# transactions async-await ms-access-2010 oledb

我在使用async / await时遇到使用事务范围回滚的问题。一切都在没有事务范围的情况下工作,但每当我故意引起异常(第二次迭代的插入上的重复主键)时,就不会发生回滚(用于更新)或任何类型的与事务相关的错误。

  • 我还应该注意除非" OLE DB服务= -4"在连接字符串中,我收到错误: " Microsoft.ACE.OLEDB.12.0' Microsoft.ACE.OLEDB.12.0'不支持ITransactionLocal接口。供应商。当前提供商无法使用本地交易。"

下面按钮事件处理程序中的代码只是测试事务范围的示例。主要目标是能够异步更新事务中包含的循环中的多个表,因此我可以避免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);
        }

2 个答案:

答案 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线程完成。希望对您有所帮助!