我想在多个表上运行多个插入语句。我正在使用 dapper.net。 我没有看到任何处理 dapper.net 事务的方法。
请分享您如何在 dapper.net 中使用事务的想法。
我想在多个表上运行多个插入语句。我正在使用 dapper.net。 我没有看到任何处理 dapper.net 事务的方法。
请分享您如何在 dapper.net 中使用事务的想法。
以下是代码片段:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
请注意,由于默认情况下没有引用System.Transactions
程序集,因此您需要添加对它的引用。
我更喜欢通过直接从连接获取交易来使用更直观的方法:
// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
connection.Execute(
"INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
transaction.Commit();
}
.BeginTransaction()
之后才能打开吗?如果是这样的话,这个扩展方法将促进错误的事务使用。(在我看来,它甚至应该抛出“无法在连接已经打开后打开事务”。) - ANevesDapper有三种处理事务的方式:
你可以从官方教程网站这里了解更多关于这些事务方式的信息。
以下是对各事务方式的详细介绍:
1. 简单事务
在此示例中,您在现有的数据库连接上创建一个事务,然后将该事务传递给dapper的Execute方法(这是一个可选参数)。
完成所有工作后,只需提交事务即可。
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
connection.Execute(sql, new {CustomerName = "Mark"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "Sam"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "John"}, transaction: transaction);
transaction.Commit();
}
}
2. 事务来自事务范围
如果您想创建一个事务范围,您需要在创建数据库连接之前执行此操作。一旦创建了事务范围,您可以执行所有操作,然后进行单个调用以完成事务,这将提交所有命令。
using (var transaction = new TransactionScope())
{
var sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = My.ConnectionFactory())
{
connection.Open();
connection.Execute(sql, new {CustomerName = "Mark"});
connection.Execute(sql, new {CustomerName = "Sam"});
connection.Execute(sql, new {CustomerName = "John"});
}
transaction.Complete();
}
3. 使用 Dapper 事务
在我看来,这是实现代码中事务最为方便易读的方法。Dapper 提供了一个扩展的 SQL 事务实现,称之为 Dapper 事务(可以在此处找到),它使你能够直接运行 SQL 执行而不需要使用事务。
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
transaction.Execute(sql, new {CustomerName = "Mark"});
transaction.Execute(sql, new {CustomerName = "Sam"});
transaction.Execute(sql, new {CustomerName = "John"});
transaction.Commit();
}
}
IDbTransaction
上添加Execute扩展方法是一个巨大的创意。 - Ian BoydIDbConnection
和IDbTransaction
。通常你只需要传递IDbConnection
,但如果你也在事务中,你就必须同时传递IDbTransaction
。直到现在我才意识到IDbTransaction
包含了它来自的IDbConnection
。所以现在我明白了25年前设计ADO.net接口的微软开发人员的想法——只传递IDbTransaction
。 - Ian Boyd由于Dapper仅运行ADO.NET命令,因此您应该能够使用TransactionScope
。
using (var scope = new TransactionScope())
{
// open connection
// insert
// insert
scope.Complete();
}
TransactionScope
的解决方案。请参见此答案。
TransactionScope
通常用于分布式事务;跨多个数据库的事务可能在不同的系统上进行。这需要对操作系统和 SQL Server 进行一些配置,否则将无法工作。如果您的所有查询针对单个数据库,则不建议使用此方法。
但是,对于单个数据库,当您需要将代码包含在不受控制的事务中时,它可能会有用。在单个数据库中,也不需要特殊配置。
connection.BeginTransaction
是 ADO.NET 语法,在单个数据库中实现事务(在 C#、VB.NET 等语言中)。它不能跨多个数据库工作。
connection.BeginTransaction()
是更好的选择。TransactionScope
,但对于原帖想要的效果来说,这种方法是低效的。我同意TransactionScope
在许多情况下都是好工具,但不适用于这种情况。 - Amit JoshiDaniel的回答对我来说效果很好。为了完整起见,这里有一个片段展示如何使用事务范围和dapper进行提交和回滚:
using System.Transactions;
// _sqlConnection has been opened elsewhere in preceeding code
using (var transactionScope = new TransactionScope())
{
try
{
long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});
transactionScope.Complete();
}
catch (Exception exception)
{
// Logger initialized elsewhere in code
_logger.Error(exception, $"Error encountered whilst executing SQL: {sqlString}, Message: {exception.Message}")
// re-throw to let the caller know
throw;
}
} // This is where Dispose is called
Dispose
方法先调用,哪个后调用,只是它被调用了两次。至于“第二次调用dispose不会有害”,那是一个很大的假设。我已经学到了文档和实际实现经常不一致的教训。但如果你想听微软的话:https://msdn.microsoft.com/zh-cn/library/ms182334.aspx?f=255&MSPPError=-2147217396 - CodeNaked
Dispose()
方法中。如果没有调用Complete()
,事务将被回滚。 - the_joric