NHibernate: перекрестная нить ленивая загрузка - PullRequest
2 голосов
/ 10 марта 2011

Я написал приложение, которое использует NHibernate для обеспечения базовой модели персистентности объекта.

Модель данных состоит из объекта с несколькими строковыми свойствами и одним свойством HashSet для хранения произвольных фрагментов данных.Это представлено в NHibernate как класс с прикрепленным к нему набором.

Ядром приложения является механизм бизнес-правил, работающий в пуле потоков.После успешного выполнения набора правил я запрашиваю NHibernate обновить объект в БД.

Поскольку он многопоточный, я выполняю вызов .OpenSession () каждый раз, когда делаю доступ к БД для возвратановый объект ISession для выполнения моей работы, избавляющийся от него после использования.

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

Я экспериментировал с использованием мьютекса для блокировки одного сеанса NHibernate между потоками и включения отложенной загрузки.Это работает, но невероятно медленно.Профилирование показывает, что на ожидание мьютекса тратится огромное количество времени - и это портит параллелизм приложения.

Есть ли способ включить отложенную загрузку в моей ситуации?Т.е. кросс-поточный доступ к БД.

Или есть другой способ решения этой проблемы?Возможно, не запускать обновление явно каждый раз, когда выполнение правила завершается?Хотя одна из моих основных причин для этого состоит в том, что в случае сбоя приложения БД представляет последнее состояние данных в приложении.

Буду признателен за любую помощь / указатели, которые вы можете дать.

1 Ответ

2 голосов
/ 10 марта 2011

Ни сеанс NHibernate не являются поточно-ориентированными, и сущности обычно не являются поточно-ориентированными. Транзакции используются для решения проблем параллелизма, поэтому не имеет смысла запускать параллельные потоки в одной транзакции.

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

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

* Решения 1008 *

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

2. Не использовать отложенную загрузку : отключите отложенную загрузку для сущностей, которые необходимы для правил. Это может быть указано в запросе.

3. Загружать значения сущностей в основной поток : это, вероятно, самый сложный способ. Напишите сервис, который запускается в основном потоке. Он принимает лямбда-выражения в качестве аргумента, которые обращаются к свойствам сущности. Выражения помещаются в очередь и выполняются в главном потоке, а результат возвращается в вызывающий поток.

var myValue = entity.ExecuteInMainThread(x => x.Property);

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


Чем дольше я думаю о проблеме, тем больше я думаю, что было бы неплохо, чтобы такая функция была реализована самими прокси. Прокси-сервер должен запустить службу, запущенную в потоке, в котором он был создан. Затем он ставит в очередь отложенную загрузку в этой службе, а не выполняет ее сам. Это будет полностью прозрачно для вызывающего кода.

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

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