2016-04-17 2 views
0

У меня есть класс репозитория NHibernate, который выполняет некоторые операции READ для нескольких таблиц за одну транзакцию.Как создать хранилища NHibernate Thread safe

Но у меня есть старый кусок кода, который пытается вызвать этот класс NHibernate на параллельные потоки, что-то вроде

someList.AsParallel().Select(x=>x.repo.GetData()); 

И операция не говоря SQL не поддерживает несколько транзакций, как может сделать ISession в потоке NHibernate безопасным?

+0

Важно ли, чтобы этот кусок кода был многопоточным? Если да, то почему? Это из-за производительности (это то, что мы могли бы решить по-другому) или объем работы по ее изменению (что не так легко решить)? –

+0

Тип приложения также имеет важное значение.Если это веб-сайт, добавление параллелизма в обработке HTTP-запросов является ужасным выбором для масштабируемости приложения и его следует избегать любой ценой. –

ответ

4

NHibernate ISession не является потокобезопасным, период.
Из NHibernate справочной документации Chapter 1, Getting started section:

ISession не является поточно-объект, который представляет собой единый блок-оф-работы с базой данных.

Вместо этого вы должны изменить свой старый код.

Этот фрагмент кода в любом случае похож на ужас кодирования. Он страдает от n + 1 нагрузки плохой практики. Обычно это происходит при неправильной настройке ленивой загрузки (забыв установить адекватное значение batch-size в сопоставлениях сущностей и коллекций, не задав параметр конфигурации default_batch_fetch_size). Но там, это явно закодировано!

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

Чтобы исправить это, вы должны загрузить все свои данные за один раз, а затем отправить его в свой список по мере необходимости. Сначала вы можете проецировать свои данные в словарь, чтобы избежать алгоритма диспетчеризации O (n²).

После того, как сделали, AsParallel должен был исчезнуть, и ваша проблема безопасности нитей тоже.

Если эта вещь слишком сложная (что больше похоже на то, что показывает ваш пример), или действительно соответствует чему-то, что необходимо сделать с помощью параллелизма, тогда вы должны создать экземпляр одного выделенного ISession для каждого GetData в вашей параллельной обработке.

1

Обратите внимание, что при использовании ленивой загрузки и прокси, даже объекты являются потокобезопасными!

  • Если запросы должны быть распараллелены, вам необходимо сделать это в отдельных транзакциях. Рассмотрим изоляцию и атомарность. Если это необходимо для одной транзакции, вам нужно улучшить производительность по-другому.
  • Если вычисления на объектах должны быть распараллелены, вы должны делать оптимизированные запросы в основном потоке, копировать данные в сущности в DTO и обрабатывать их в нескольких потоках. Не обращайтесь к объектам из фоновых потоков!

 Смежные вопросы

  • Нет связанных вопросов^_^