Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Transactions 企业库:回滚多个事务_Transactions_Enterprise Library - Fatal编程技术网

Transactions 企业库:回滚多个事务

Transactions 企业库:回滚多个事务,transactions,enterprise-library,Transactions,Enterprise Library,我目前正在使用Microsoft Enterprise Library 5.0,我想知道下面的代码是否是处理事务的公认方法 我已经将场景简化了一点,但本质是我希望在同一事务中的不同数据库中执行多个插入 如果其中一个插入失败,则应回滚所有事务 我已经查看了交易范围,但我想知道如果没有它,我是否可以管理 public void InsertStuff_AcrossDbs() { //Create a ref to 2 different Db's on the same server

我目前正在使用Microsoft Enterprise Library 5.0,我想知道下面的代码是否是处理事务的公认方法

我已经将场景简化了一点,但本质是我希望在同一事务中的不同数据库中执行多个插入

如果其中一个插入失败,则应回滚所有事务

我已经查看了
交易范围
,但我想知道如果没有它,我是否可以管理

public void InsertStuff_AcrossDbs()
{
    //Create a ref to 2 different Db's on the same server
    Database db_a = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_a"); 
    Database db_b = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_b");

    //Create Connections for the 2 db's
    using (DbConnection connection_db_a = db_a.CreateConnection())
    using (DbConnection connection_db_b = db_b.CreateConnection())
    {
        //Create DbTransactions for the 2 db's
        DbTransaction transaction_dbA = connection_db_a.BeginTransaction();
        DbTransaction transaction_dbB = connection_db_b.BeginTransaction();

        try
        {
            //Insert into DbA.Person and get the PK
            DbCommand dbCmd_dbA_insert = db_a.GetSqlStringCommand("Insert INTO Person(Name,Age)Values('test',23); SET @pkReturnId= SCOPE_IDENTITY() ");
            db_a.AddOutParameter(dbCmd_dbA_insert, "pkReturnId", DbType.Int32, 0);
            db_a.ExecuteNonQuery(dbCmd_dbA_insert, transaction_dbA);
            int personID = Convert.ToInt32(db_a.GetParameterValue(dbCmd_dbA_insert, "@pkReturnId"));

            //Insert 'personId' into dbB.Employee  (a different table in a different db)
            DbCommand dbCmd_dbB_delete = db_a.GetSqlStringCommand("Insert INTO Employee(personId) VALUES(" + personID + ")");
            db_a.ExecuteNonQuery(dbCmd_dbB_delete, transaction_dbB);

            //try to commit both transactions
            transaction_dbA.Commit();
            transaction_dbB.Commit();
        }
        catch (Exception ex)
        {
            //If either transactions fails, roll back both
            try
            {
                transaction_dbA.Rollback();
            }
            catch { }

            try
            {
                transaction_dbB.Rollback();
            }
            catch { }

            throw ex;
        }
        finally
        {
            connection_db_a.Close();
            connection_db_b.Close();
        }

    }

}

此代码是否被认为是正常的,或者是否会出现这样的情况:如果其中一个事务抛出错误,则并非所有事务都将回滚?

您的代码是正常的。存在两个数据库不一致的情况

在代码中,您正在创建两个本地事务:一个在数据库A中,一个在数据库B中。这不是您想要的,因为您希望两个操作都发生在一个事务中,以保持一致性。要做到这一点,您需要使用分布式事务,正如您所提到的,这是最好的方法。它还将使代码更具可读性

e、 g

我意识到您的代码是一个简化的场景,所以我不确定这些是否适用于您的实际代码,但这里有一些其他注释:

DbCommand dbCmd_dbB_delete = 
    db_a.GetSqlStringCommand("Insert INTO Employee(personId) VALUES(" + personID + ")");
应避免使用动态SQL字符串。它们容易受到SQL注入攻击,而且性能也较低,因为数据库执行计划不会被其他具有不同参数的请求重用

finally
{
    connection_db_a.Close();
    connection_db_b.Close();
}
您不需要手动关闭连接,因为您正在通过using语句处理连接,而close和Dispose在功能上是等效的

finally
{
    connection_db_a.Close();
    connection_db_b.Close();
}