在 transactionScope 中删除用户时超时
timeout when deleting user inside of transactionScope
- 背景
我们正在尝试存档旧用户数据,以保持我们最常见的 table 更小。
问题
用于删除记录的普通 EF 代码适用于我们的自定义 tables。 AspNetUsers table 是另一回事。似乎这样做的方法是使用 _userManager.Delete 或 _userManager.DeleteAsync。这些工作无需尝试在一个事务中执行多个数据库调用。当我将其包装在 transactionScope 中时,它会超时。这是一个例子:
public bool DeleteByMultipleIds(List<string> idsToRemove)
{
try
{
using (var scope = new TransactionScope())
{
foreach (var id in idsToRemove)
{
var user = _userManager.FindById(id);
//copy user data to archive table
_userManager.Delete(user);//causes timeout
}
scope.Complete();
}
return true;
}
catch (TransactionAbortedException e)
{
Logger.Publish(e);
return false;
}
catch (Exception e)
{
Logger.Publish(e);
return false;
}
}
请注意,虽然代码是 运行,但我直接调用数据库,例如:
DELETE
FROM ASPNETUSERS
WHERE Id = 'X'
也会超时。此 SQL 在执行 C# 代码之前起作用。因此,看起来超过 1 db hit 似乎锁定了 table。如何在一次事务中找到用户(数据库命中 #1)并删除用户(数据库命中 #2)?
Microsoft 的建议是在与 EF 进行交易时使用不同的 API。这是由于 EF 和 TransactionScope class 之间的交互。隐式事务范围迫使事物可序列化,这会导致死锁。
对 EF 内部 API 的详细描述如下:MSDN Link
作为参考,您可能需要查看用户管理器是否公开数据上下文并将您的事务范围替换为 using(var dbContextTransaction = context.Database.BeginTransaction()) { //code }
或者,看看你的场景,你实际上很安全地找到用户 ID,然后尝试删除它,如果用户在找到它和删除它。
对我来说,问题涉及在同一事务中使用多个单独的 DbContext
。 BeginTransaction()
方法无效。
在内部,UserManager.Delete()
正在调用 RunSync()
包装器中的 async
方法。因此,为我的 TransactionScope
使用 TransactionScopeAsyncFlowOption.Enabled
参数确实有效:
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
_myContext1.Delete(organisation);
_myContext2.Delete(orders);
_userManager.Delete(user);
scope.Complete();
}
- 背景
我们正在尝试存档旧用户数据,以保持我们最常见的 table 更小。
问题
用于删除记录的普通 EF 代码适用于我们的自定义 tables。 AspNetUsers table 是另一回事。似乎这样做的方法是使用 _userManager.Delete 或 _userManager.DeleteAsync。这些工作无需尝试在一个事务中执行多个数据库调用。当我将其包装在 transactionScope 中时,它会超时。这是一个例子:
public bool DeleteByMultipleIds(List<string> idsToRemove) { try { using (var scope = new TransactionScope()) { foreach (var id in idsToRemove) { var user = _userManager.FindById(id); //copy user data to archive table _userManager.Delete(user);//causes timeout } scope.Complete(); } return true; } catch (TransactionAbortedException e) { Logger.Publish(e); return false; } catch (Exception e) { Logger.Publish(e); return false; } }
请注意,虽然代码是 运行,但我直接调用数据库,例如:
DELETE
FROM ASPNETUSERS
WHERE Id = 'X'
也会超时。此 SQL 在执行 C# 代码之前起作用。因此,看起来超过 1 db hit 似乎锁定了 table。如何在一次事务中找到用户(数据库命中 #1)并删除用户(数据库命中 #2)?
Microsoft 的建议是在与 EF 进行交易时使用不同的 API。这是由于 EF 和 TransactionScope class 之间的交互。隐式事务范围迫使事物可序列化,这会导致死锁。
对 EF 内部 API 的详细描述如下:MSDN Link
作为参考,您可能需要查看用户管理器是否公开数据上下文并将您的事务范围替换为 using(var dbContextTransaction = context.Database.BeginTransaction()) { //code }
或者,看看你的场景,你实际上很安全地找到用户 ID,然后尝试删除它,如果用户在找到它和删除它。
对我来说,问题涉及在同一事务中使用多个单独的 DbContext
。 BeginTransaction()
方法无效。
在内部,UserManager.Delete()
正在调用 RunSync()
包装器中的 async
方法。因此,为我的 TransactionScope
使用 TransactionScopeAsyncFlowOption.Enabled
参数确实有效:
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
_myContext1.Delete(organisation);
_myContext2.Delete(orders);
_userManager.Delete(user);
scope.Complete();
}