linq to sql с проблемой блокировки таблицы nservicebus - PullRequest
1 голос
/ 23 апреля 2010

Я строю систему с использованием NServiceBus, а мой DataLayer использует SQL Linq 2.

Система состоит из 2 сервисов.

Сервис1 получает сообщения от NSB. Он запросит Table1 в моей базе данных и вставляет запись в Table1 Если определенное условие выполнено, новое сообщение NSB отправляется во 2-ю услугу

Служба2 будет обновлять записи также в Таблице1, когда она получает сообщения от Службы1 и выполняет другую работу, не связанную с базой данных. Service2 - это длительный процесс.

Проблема, с которой я столкнулся, заключается в том, что Service2 обновляет запись в Table1, таблица заблокирована. Кажется, блокировка установлена ​​до тех пор, пока Service2 не завершит всю свою обработку. Т.е. блокировка не снимается после удаления моего текста данных.

Это приводит к тайм-ауту запроса в Service1. Как только Service2 завершит обработку, Service1 возобновит обработку снова без проблем.

Так, например, код Service1 может выглядеть так:

int x =0;
using (DataContext db = new DataContext())
{
  x = (from dp in db.Table1 select dp).Count(); // this line will timeout while service2 is processing

  Table1 t = new Table1();
  t.Data = "test";
  db.Table1.InsertOnSubmit(t);
  db.SubmitChanges();
}

if(x % 50 == 0)
  CallService2();

Код в service2 может выглядеть так:

using (DataContext db = new DataContext())
{
  Table1 t = db.Table1.Where(t => t.id == myId);
  t.Data = "updated";

  db.SubmitChanges();

}

// I would have expected the lock to have been released at this point, but this is not the case.

DoSomeLongRunningTasks();

// lock will be released once service2 exits

Я не понимаю, почему блокировка не снимается, когда текст данных располагается в Service2.

Чтобы обойти проблему, я звонил:

db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");

и это работает, но я не рад его использованию. Я хочу решить эту проблему правильно.

Кто-нибудь сталкивался с подобной проблемой раньше, и знает ли кто-нибудь, как ее решить? Почему блокировка не снимается после удаления текста данных?

Заранее спасибо.

p.s. извините за очень длинный пост.

EDIT:

глядя на это в реальной ситуации (например, доставка):

service1 добавляет записи ящиков в базу данных. ящик добавляется в запись контейнера (если запись контейнера не существует, она создается) если существует определенное количество записей или ящиков, создайте запись об отправке, закройте все контейнеры и назначьте запись об отгрузке.

затем вызовите service2 для обработки записи об отправке. вызов service2 - это вызов Bus.Send, но он может быть частью саги. service2 будет обновлять каждую запись ящика, для которого она назначена. затем обрабатываются некоторые другие инструкции по доставке. пока service2 обрабатывает, для следующей отправки может быть получено больше ящиков, но в таком виде они не могут быть назначены контейнерам, пока service2 не завершит обработку отправки.

1 Ответ

4 голосов
/ 23 апреля 2010

Причина, по которой вы видите такое поведение, заключается в том, что уровень изоляции по умолчанию, используемый NServiceBus (то же самое для TransactionScope), является Serializable - который блокирует всю таблицу.

То, что вы хотите сделать, это установить другой уровень изоляции на уровне NServiceBus.

Чтобы сделать это, вам нужно будет использовать свободный API инициализации и после вызова .MsmqTransport () вызвать метод .IsolationLevel (IsolationLevel.ReadCommitted) или передать какое-то другое значение. Я не рекомендую идти ниже этого уровня (например, читать без ответа).

В сценарии, описанном выше, я бы не стал помещать все это в один обработчик, предпочитая использовать сагу для управления потоком верхнего уровня, поскольку вы, кажется, достаточно счастливы, чтобы нарушить границы изоляции в середине вашего обработчика.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...