Разбираюсь в не своем коде, там много обращений в БД(MS SQL SERVER) с использованием generic репозитория и много очень запутанного кода(поэтому его демонстрации не будет).
Бывает такое что при работе вылетает exception deadlock на методе выборки из базы.
Если упростить описание этого процесса, то для выборки из DbSet<TEntity>
применяются данные методы :
IQueryable.OrderByDescending
Queryable.Where
Queryable.Skip
QueryableExtensions.Include
До и после этой выборки, но до применения общего context.SaveChanges
могут происходить любые Update Insert Delete Select в любых количествах.
Искал как может происходить deadlock и находил только описание случая с 2 транзакциями на Update которые блокируют ресурсы друг друга. Но в случае с Select не понимаю как такое может произойти. Буду рад примеру такой ситуации.
Не очень разбираюсь, но возможно изолированность транзакций как то может влиять на это. Или может это проблемы на стороне c#, а не базы.
System.Data.Entity.Core.EntityCommandExecutionExce
ption: An error occurred while reading from the store provider's data reader. Se
e the inner exception for details. ---> System.Data.SqlClient.SqlException: Tran
saction (Process ID 106) was deadlocked on lock resources with another process a
nd has been chosen as the deadlock victim. Rerun the transaction.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolea
n breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception
, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObj
ect stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand
cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler,
TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Bo
olean& more)
at System.Data.SqlClient.SqlDataReader.Read()
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead
()
--- End of inner exception stack trace ---
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.HandleRea
derException(Exception e)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead
()
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnu
merator.MoveNext()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Deadlock вполне может возникнуть при SELECT. На самом деле для возникновения дедлока неважна конкретная операция. Важен сам факт установки блокировки, который вызывает Deadlock.
Сильно упрощенный пример::
По умолчанию SELECT ставит S-локи. UPDATE - ставит X-локи.
S и X-локи несовместимы - их нельзя одновременно поставить на один и тот же объект. Тот, кто попытается поставить лок вторым, будет ждать, пока первый его снимет.
У вас одновременно выполняются две транзакции:
UPDATE A...
)UPDATE B...
)SELECT FROM B...
). Ждет, пока будет снят существующий лок от транзакции 2.SELECT FROM A...
). Ждет, пока будет снят существующий лок от транзакции 1.Пример очень сильно упрощен, гранулярность локов может быть разная (строка, таблица, страница и т.д.), SQL Server умеет повышать гранулярность вверх. Но общая картина все равно та же.
Стандартный способ избежать дедлоков на чтении - перейти на уровень изоляции транзакций, в котором SELECT не ставит локи. Это или SNAPSHOT, или READ COMMITTED SNAPSHOT.
Эти уровни изоляции транзакций используют row versioning вместо блокировок, и SELECT-ы при них читают копию данных, если к моменту чтения есть незакомитанные изменения другой транзакции.
Разница между ними - в обработке записи. READ COMMITTED SNAPSHOT ведет себя как обычный READ COMMITTED, и просто ставит U/X локи. SNAPSHOT пишет в копию, и падает на коммите транзакции, если кто-то уже успел записать до него.
Если у вас уже используется READ COMMITTED (он почти всегда и везде используется по умолчанию), то достаточно просто включить READ COMMITTED SNAPSHOT на уровне базы, и дедлоки пропадут:
ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
Отдельно стоит упомянуть работу с транзакциями через TransactionScope. Этот замечательный класс по умолчанию переписывает стандартный для EF и SQL Server уровень READ COMMITTED на SERIALIZABLE, что почти гарантирует дедлоки. Если пользуетесь им - не забывайте вручную выставлять нужный вам уровень изоляции в конструкторе.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня есть вот такая строчка в С++ коде: sects[low]bound = low
Подскажите пожалуйста! Имеется контроллер на aspnet в котором получаю список из базы данных, далее этот список надо отправить на мобильное приложение
Использую SQL Server 2014, VS 2017 Суть в том, что нужно по параметрам создавать отчеты, например, вывести какие-нибудь записи за указанный период времениЯ...