MySQL - DBUpdateException ('обнаружена тупиковая ситуация при попытке получить блокировку; попробуйте перезапустить транзакцию') - PullRequest
0 голосов
/ 13 января 2019

У меня есть приложение MVC в .NET Core использует MySQL. У меня есть функция загрузки, где идентификатор передается для загрузки файла. Однако ошибки продолжают возникать, и кажется, что приложение почему-то становится менее отзывчивым на сервере, как будто оно перерабатывается. следующий код показывает часть, ответственную за загрузку файла. Я использую 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()

Я не понимаю, как происходит тупик и как его решить

Ответы [ 3 ]

0 голосов
/ 13 января 2019

Можете ли вы попробовать еще одну вещь. Просто быстрое решение

//replace your line with this
if (download == null) {
    context.SaveChanges();
    scope.Complete();
    throw new InvalidOperationException("Cannot find ProjectDownload.Id");
}
0 голосов
/ 14 января 2019

Попробуйте поставить эти перед использованием Область транзакций :

 
ProjectDownload download = context.ProjectDownload.Where(d => d.Id == downloadId).FirstOrDefault();
Project proj = context.Project.Where(p => p.ProjectDownload.Any(pd => pd.Id == downloadId)).FirstOrDefault();

0 голосов
/ 13 января 2019

Проблема в том, что вы не блокируете определенную запись. В 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  
}
...