MySQL - DBUpdateException ('Deadlock found when trying to get lock; try restarting transaction')
MySQL - DBUpdateException ('Deadlock found when trying to get lock; try restarting transaction')
我有一个 .NET Core 中的 mvc 应用程序使用 MySQL。我有一个下载功能,其中传递 id 以下载文件。但是,错误不断发生,并且似乎不知何故,应用程序在服务器上的响应速度变慢了,就好像它正在被回收一样。以下代码显示了负责下载文件的部分。我正在使用 TransactionScope 来确保下载计数器已正确更新。我得到的错误与死锁有关。是否有人可以指出问题出在哪里?
using (var context = new MyDbContext())
using (TransactionScope scope = new TransactionScope())
{
ProjectDownload download = context.ProjectDownload.Include(pd => pd.Project).Where(d => d.Id == downloadId).FirstOrDefault();
if (download == null) throw new InvalidOperationException("Cannot find ProjectDownload.Id");
download.DownloadCounter++;
download.Project.DownloadCounter++;
try
{
context.SaveChanges();
scope.Complete();
return (ProjectDownloadModel)download;
}
catch (DbUpdateException ex){
throw;
}
}
也试过这种方式将之前的代码改成:
using (var context = new MyDbContext())
using (TransactionScope scope = new TransactionScope())
{
ProjectDownload download = context.ProjectDownload.Where(d => d.Id == downloadId).FirstOrDefault();
download.DownloadCounter++;
Project proj = context.Project.Where(p => p.ProjectDownload.Any(pd => pd.Id == downloadId)).FirstOrDefault();
proj.DownloadCounter++;
...
出现以下错误:
Exception has occurred: CLR/MySql.Data.MySqlClient.MySqlException
An exception of type 'MySql.Data.MySqlClient.MySqlException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code: 'Deadlock found when trying to get lock; try restarting transaction'
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__17`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at ProjectProcess.DownloadProject(Int32 downloadId) in C:\Users\Projects\ProjectWebsite\BusinessLogic\ProjectProcess.cs:line 124
at ProjectController.DownloadProject(Int32 downloadID) in C:\Users\Projects\ProjectWebsite\Controllers\ProjectController.cs:line 33
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
不明白死锁是怎么发生的,怎么解决
问题是您没有锁定某些记录。在 mysql 中,您可以像这样锁定行
SELECT * FROM users WHERE name = 'name' FOR UPDATE;
但是对于你的问题,你可以试试这个。希望能解决你的问题
using (var scope = new TransactionScope(TransactionScopeOption.RequireNew,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
// your select and increment should go here
}
你能再试试一件事吗?快速修复
//replace your line with this
if (download == null) {
context.SaveChanges();
scope.Complete();
throw new InvalidOperationException("Cannot find ProjectDownload.Id");
}
在使用事务范围之前尝试将这些:
ProjectDownload download = context.ProjectDownload.Where(d => d.Id == downloadId).FirstOrDefault();
Project proj = context.Project.Where(p => p.ProjectDownload.Any(pd => pd.Id == downloadId)).FirstOrDefault();
我有一个 .NET Core 中的 mvc 应用程序使用 MySQL。我有一个下载功能,其中传递 id 以下载文件。但是,错误不断发生,并且似乎不知何故,应用程序在服务器上的响应速度变慢了,就好像它正在被回收一样。以下代码显示了负责下载文件的部分。我正在使用 TransactionScope 来确保下载计数器已正确更新。我得到的错误与死锁有关。是否有人可以指出问题出在哪里?
using (var context = new MyDbContext())
using (TransactionScope scope = new TransactionScope())
{
ProjectDownload download = context.ProjectDownload.Include(pd => pd.Project).Where(d => d.Id == downloadId).FirstOrDefault();
if (download == null) throw new InvalidOperationException("Cannot find ProjectDownload.Id");
download.DownloadCounter++;
download.Project.DownloadCounter++;
try
{
context.SaveChanges();
scope.Complete();
return (ProjectDownloadModel)download;
}
catch (DbUpdateException ex){
throw;
}
}
也试过这种方式将之前的代码改成:
using (var context = new MyDbContext())
using (TransactionScope scope = new TransactionScope())
{
ProjectDownload download = context.ProjectDownload.Where(d => d.Id == downloadId).FirstOrDefault();
download.DownloadCounter++;
Project proj = context.Project.Where(p => p.ProjectDownload.Any(pd => pd.Id == downloadId)).FirstOrDefault();
proj.DownloadCounter++;
...
出现以下错误:
Exception has occurred: CLR/MySql.Data.MySqlClient.MySqlException
An exception of type 'MySql.Data.MySqlClient.MySqlException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code: 'Deadlock found when trying to get lock; try restarting transaction'
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__17`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at ProjectProcess.DownloadProject(Int32 downloadId) in C:\Users\Projects\ProjectWebsite\BusinessLogic\ProjectProcess.cs:line 124
at ProjectController.DownloadProject(Int32 downloadID) in C:\Users\Projects\ProjectWebsite\Controllers\ProjectController.cs:line 33
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
不明白死锁是怎么发生的,怎么解决
问题是您没有锁定某些记录。在 mysql 中,您可以像这样锁定行
SELECT * FROM users WHERE name = 'name' FOR UPDATE;
但是对于你的问题,你可以试试这个。希望能解决你的问题
using (var scope = new TransactionScope(TransactionScopeOption.RequireNew,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
// your select and increment should go here
}
你能再试试一件事吗?快速修复
//replace your line with this
if (download == null) {
context.SaveChanges();
scope.Complete();
throw new InvalidOperationException("Cannot find ProjectDownload.Id");
}
在使用事务范围之前尝试将这些:
ProjectDownload download = context.ProjectDownload.Where(d => d.Id == downloadId).FirstOrDefault(); Project proj = context.Project.Where(p => p.ProjectDownload.Any(pd => pd.Id == downloadId)).FirstOrDefault();