gpt4 book ai didi

transactions - 企业库: Roll back multiple transactions

转载 作者:行者123 更新时间:2023-12-04 06:32:45 26 4
gpt4 key购买 nike

我目前正在使用 Microsoft Enterprise Library 5.0,我想知道下面的代码是否是处理事务的可接受方式。

我已经稍微简化了场景,但本质是我想在同一个事务中在不同的数据库中执行多个插入。

如果任一插入失败,则所有事务都应回滚。

我看过 TransactionScope ,但我想知道如果没有它我是否可以管理。

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 中。这不是您想要的,因为您希望两个操作都发生在一个事务中以保持一致性。为此,您需要使用分布式事务,正如您所提到的, TransactionScope 是最好的方法。它还将使代码更具可读性。

例如

Database db_a = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_a"); 
Database db_b = DatabaseFactory.CreateDatabase("Data Source=localhost;Initial Catalog=db_b");

using (TransactionScope scope = new TransactionScope())
{
using (DbConnection connA = db_a.CreateConnection())
{
// ...
}

using (DbConnection connB = db_b.CreateConnection())
{
// ...
}

scope.Complete();
}

我意识到您的代码是一个简化的场景,所以我不确定这些是否适用于您的实际代码,但这里有一些其他评论:
DbCommand dbCmd_dbB_delete = 
db_a.GetSqlStringCommand("Insert INTO Employee(personId) VALUES(" + personID + ")");

应避免使用动态 SQL 字符串。它们容易受到 SQL 注入(inject)攻击并且性能也较低,因为数据库执行计划不会被其他具有不同参数的请求重用。
finally
{
connection_db_a.Close();
connection_db_b.Close();
}

您不需要手动关闭连接,因为您通过 using 语句处理连接,并且 Close 和 Dispose 在功能上是等效的。

关于transactions - 企业库: Roll back multiple transactions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5196851/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com