SqlBulkCopy在事务内部插入时会阻止对表的任何其他写入
本文关键字:任何 其他 事务 内部 插入 SqlBulkCopy | 更新日期: 2023-09-27 18:26:23
在我的web应用程序中,用户可以同时插入大量数据,以提高我使用SqlBulkCopy
类的性能。对于插入到两个不同表中的单个操作,它会运行多次。如果用户取消操作或操作失败,那么我需要回滚数据,以便使用隔离级别的快照将所有内容封装在事务中。
我的理解是,使用快照隔离将允许其他用户同时写入/读取表。但是,当进行一次数据上载时,它将阻止对表的任何其他写入,直到整个父事务完成。
以下是一些显示问题的简化代码。我排除了很多功能,但想法保持不变。我对内存中的某个集合进行迭代,将它们批量复制到一个表,取回它们,然后批量复制到另一个表。
using (var transaction = myDbContext.Database.BeginTransaction(
System.Data.IsolationLevel.Snapshot))
{
var myCollectionOfObjects;
while(!GetData(ref myCollectionOfObjects))
{
SqlBulkCopy bulkCopy = new SqlBulkCopy(myCon, transaction);
//Sets the columns + rows
SetUp(bulkCopy);
bulkCopy.WriteToServer();
//After the bulkcopy operation is complete
// we retrieve the rows inserted and do another bulk copy to a different table
var recentlyAddedRows = GetRecentlyAddedRow();
SqlBulkCopy otherTableBulkCopy = new SqlBulkCopy(myCon, transaction);
SetUpBulkCopyForOtherTable(otherTableBulkCopy);
otherTableBulkCopy.WriteToServer();
}
transaction.Commit();
}
因此,如果一个用户当前在该事务中,即使它正在回滚,也会阻止所有其他向表写入的事务,因此其他执行相同功能或试图向表写入内容的用户也会被阻止。
这是预期的行为吗?有没有办法绕过这一点?
编辑
通过查看SQL中应用的锁,这似乎是由于bulkcopy类导致在表对象上设置了一个排他锁(X),而就好像一次插入一个锁一样,表上只应用了一个意向锁(IX)。仍然不确定是否有办法解决这个问题,但我认为这是由于锁定升级。
在我的一些测试中,更改表索引上的"允许页面锁定"和更改大容量副本的批量大小已经绕过了完全锁定,但它们是不稳定的。
IsolationLevel
仅指读取,不指写入。如果您的一个客户端正在写入数据,那么另一个客户端应该能够读取事务开始前的数据,但是,它将无法同时写入。
要减少阻塞时间,可以做的一件事是大容量复制到(唯一的)暂存表中,而不是直接复制到目标表中。这根本不需要在事务中。一旦所有数据都在暂存表中,就将其复制到事务中的目标表中。这不会完全阻止阻止的可能性。然而,从数据库中复制数据通常会很快,尤其是当数据可能被缓存时。唯一潜在的棘手之处是创建uique暂存表(如果它们不是唯一的,只需将问题从一个表转移到另一个表)。