【发布时间】:2018-12-06 11:19:40
【问题描述】:
我们有一个 webapi,它处理大量请求,有时每秒处理大量请求,并且在每个请求开始时,我们使用 Entity 框架向我们的日志表发送一个日志条目。
但是,我们日志表的这个条目通常会在另一个进程上死锁,我不明白是什么原因造成的。
using (UnitOfWork unitofwork = new UnitOfWork())
{
unitofwork.WebApiRequestLogRepository.Insert(new WebApiRequestLog
{
Created = DateTime.Now,
Username = System.Threading.Thread.CurrentPrincipal.Identity.Name,
Controller = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName,
Method = actionContext.ActionDescriptor.ActionName,
MethodParameters = xml,
ApplicationVersion = AppSettings.Instance.Version,
Url = HttpContext.Current.Request.Url.ToString(),
});
unitofwork.Save();
}
unitofwork 是对单个上下文的封装,可以同时进行多项更改。保存调用 context.SaveChanges
实体框架生成的SQL代码
INSERT [log].[WebApiRequestLog]([Created], [Username], [Controller], [Method], [ApplicationVersion], [Url], [MethodParameters])
VALUES (@0, @1, @2, @3, @4, @5, @6)
SELECT [Id]
FROM [log].[WebApiRequestLog]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
谁能解释一下为什么单次插入日志表会导致死锁?
编辑
public virtual void Insert(TEntity entity)
{
DbSet.Add(entity);
}
public void Save()
{
StringBuilder builder = new StringBuilder();
try
{
_context.Database.Log = s => builder.AppendLine(s);
_context.SaveChanges();
}
catch (DbEntityValidationException e)
{
HandleDbEntityValidationException(e);
}
catch (Exception e)
{
Exception ex = new Exception(builder.ToString(), e);
throw ex;
}
}
【问题讨论】:
-
我们可能需要实现
UnitOfWork和WebApiRequestLogRepository.Insert才能知道是什么原因造成的。那里有任何锁定/交易吗? -
查看例如:docs.microsoft.com/en-us/sql/tools/sql-server-profiler/… 以获取有关实际锁定内容的更多信息。这可以让您找出它被锁定的原因。
-
您是否使用了已提交读快照隔离?如果不是这样,您很容易从中获得死锁,因为每个选择也会添加锁。
-
@Wanton:我不知道,我认为这是数据库设置?我在哪里可以看到我的数据库正在使用哪种隔离?
-
默认为 Read Committed 或 Read Committed 快照已启用,这将是默认设置,如果不使用 WITH 提示,您将无法再使用 Read Committed 隔离。启用读取已提交快照时的警告词 某些带有插入和更新的查询可能具有以前的竞争条件。
SELECT is_read_committed_snapshot_on FROM sys.databases WHERE [name] = 'MyDB'1 表示启用。有关两个快照隔离的更多信息docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/…
标签: c# sql-server entity-framework deadlock