事务范围和任务。当全部执行时
意图:通过事务提交/回滚支持加速 Sql 插入操作
- 有相当大的数据量(大约 900 k 个实体)
- 想要将数据并行放入 SQL 表,要拆分每个连接的数据(例如 3 个活动连接,因此每个连接 300 k)
- 如果出现问题,希望有可能回滚,因此尝试使用事务范围(嵌套-TransactionScopeOption。必需)
问题:
看起来事务范围无法支持这种类型的Task.WhenAll,因此,如果执行期间出现错误,中间写入将不会回滚
问:所以我想知道它是否可以解决,或者它只是不适当的方式来利用事务范围?
public void Upsert(IEnumerable<IEnumerable<Item>> splitPerConnection, DateTime endDate)
{
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
{
try
{
UpdateEndDate(endDate);
var insertTasks = splitPerConnection.Select(ch => Task.Run(() => Insert(ch)));
Task.WhenAll(insertTasks).GetAwaiter().GetResult();
scope.Complete();
}
catch (Exception ex)
{
throw ex;
}
}
}
private int Insert(IEnumerable<Item> items)
{
int affectedRows;
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
using (var sqlConnection = new SqlConnection(DockerMsSqlServerConnectionString))
{
sqlConnection.Open();
affectedRows = sqlConnection.Execute(ItemsQueries.Insert, items, commandTimeout: 0);
scope.Complete();
}
return affectedRows;
}
private int UpdateEndDate(DateTime endDate)
{
int affectedRows;
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
using (var sqlConnection = new SqlConnection(DockerMsSqlServerConnectionString))
{
sqlConnection.Open();
affectedRows = sqlConnection.Execute(ItemsQueries.UpdateEndDate, new { EndDate = endDate }, commandTimeout: 0);
scope.Complete();
}
return affectedRows;
}
Intention: speed up Sql insert operation with a transaction commit / rollback support
- Have a pretty big amount of data (about 900 k entities)
- Would like to put down the data to SQL table in parallel, gonna to split the data per connection (e.g. 3 active connections, thus 300 k per a connection)
- Would like to have possibility to rollback if something goes wrong, so try to using Transaction Scope (nested-TransactionScopeOption.Required)
Issue:
It looks like Transaction scope couldn't support such kind of Task.WhenAll thus, if ever there will be an error during execution the intermediate writes won't be rollback
Q: So I've wondered if it can be work around, or it just not appropriate way to leverage the transaction scope ?
public void Upsert(IEnumerable<IEnumerable<Item>> splitPerConnection, DateTime endDate)
{
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
{
try
{
UpdateEndDate(endDate);
var insertTasks = splitPerConnection.Select(ch => Task.Run(() => Insert(ch)));
Task.WhenAll(insertTasks).GetAwaiter().GetResult();
scope.Complete();
}
catch (Exception ex)
{
throw ex;
}
}
}
private int Insert(IEnumerable<Item> items)
{
int affectedRows;
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
using (var sqlConnection = new SqlConnection(DockerMsSqlServerConnectionString))
{
sqlConnection.Open();
affectedRows = sqlConnection.Execute(ItemsQueries.Insert, items, commandTimeout: 0);
scope.Complete();
}
return affectedRows;
}
private int UpdateEndDate(DateTime endDate)
{
int affectedRows;
using (var scope = _transactionScopeFactory.Create(TransactionScopeOption.Required))
using (var sqlConnection = new SqlConnection(DockerMsSqlServerConnectionString))
{
sqlConnection.Open();
affectedRows = sqlConnection.Execute(ItemsQueries.UpdateEndDate, new { EndDate = endDate }, commandTimeout: 0);
scope.Complete();
}
return affectedRows;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以尝试利用 SqlBulkCopy,而不是将项目拆分到不同的连接对象上。
快速向 SQL Server 插入 200 万行
您可以创建一个通过修改
IEnumerable
来获取数据集。所有并行操作都可以在此处应用以从IEnumerable
转换为数据集。创建数据集后,SqlBulkCopy 将为您提供帮助。您可以创建3-4组数据集并执行插入查询3-4次。通过这种方法,您可以维护一个数据库连接,这也有助于遵循数据库事务的 ACID 合规性。
You can try to leverage SqlBulkCopy, instead of splitting the items over different connection objects.
Insert 2 million rows into SQL Server quickly
You can create a dataset by modifying
IEnumerable<Item>
. All the parallel operations can be applied here to convert fromIEnumerable<Item>
to dataset. Once dataset is created, SqlBulkCopy will help you. You can create 3-4 sets of datasets and execute the insert query 3-4 times.In this approach, you can maintain one database connection that also helps to follow ACID compliance of the database transactions.