Управление сеансом NHibernate в приложениях Windows Service
Я разрабатываю и приложение, которое работает как служба Windows. Существуют и другие компоненты, которые включают в себя несколько служб WCF, клиентский графический интерфейс и т.д., Но именно служба Windows обращается к базе данных.
Таким образом, приложение является долговременным сервером, и я хотел бы улучшить его производительность и масштабируемость, я пытался улучшить доступ к данным между прочим. Я отправил в другой поток о кэшировании второго уровня.
Это сообщение об управлении сеансом для длинного потока, который обращается к базе данных.
Должен ли я использовать поток-статический контекст?
Если да, то есть ли какой-нибудь пример того, как это будет реализовано.
Каждый, кто находится в сети, который использует NHibernate, кажется, сильно сосредоточен на архитектуре стиля веб-приложений. Кажется, что существует большая нехватка документации/обсуждения для проектов, отличных от веб-приложений.
В настоящий момент мой длинный поток работает так:
- Вызов 3 или 4 метода DAO
- Проверить состояние возвращенных объектов.
- При необходимости обновите состояние.
- Вызов нескольких методов DAO для сохранения обновленных экземпляров. (передать идентификатор объекта и самого экземпляра), DAO снова извлечет объект из БД и задает обновленные значения и session.SaveOrUpdate() перед совершением транзакции.
- Сон для 'n' секунд
- Повторите все заново!
Итак, следующее общее правило, которое мы используем для каждого из методов DAO:
- Открыть сеанс с использованием sessionFactory.OpenSession()
- Начать транзакцию
- Работает ли db. извлечение/обновление и т.д.
- Commit trans
- (Откат в случае исключения)
- Наконец, всегда удаляйте транзакцию и session.Close()
Это происходит для каждого вызова метода для класса DAO.
Я подозреваю, что это своего рода анти-шаблон, как мы это делаем.
Тем не менее, я не могу найти достаточно места в любом месте относительно того, как мы могли бы его улучшить.
Обратите внимание, что хотя этот поток работает в фоновом режиме, делая свои вещи, есть запросы, поступающие от клиентов WCF, каждый из которых может выполнять 2-3 вызова DAO - иногда запрос/обновление тех же объектов в течение длительного времени поток имеет дело с.
Будут высоко оценены любые идеи/предложения/указатели для улучшения нашего дизайна.
Если мы сможем продолжить обсуждение, мы могли бы сделать это wiki сообщества и, возможно, ссылаться здесь на http://nhibernate.info
Krishna
Ответы
Ответ 1
Кажется, что существует большая нехватка документации/обсуждения для проектов, отличных от веб-приложений.
Это также был мой опыт. Однако модель, о которой вы следите, кажется мне верной. Вы всегда должны открывать сеанс, фиксировать изменения, а затем закрывать его снова.
Ответ 2
Этот вопрос сейчас немного старый, но другой метод заключается в использовании контекстных сеансов, а не в создании нового сеанса в каждом DAO.
В нашем случае мы собираемся создать сеанс один раз в потоке (для нашей многопоточной службы win32) и сделать его доступным для DAO, используя либо свойство, которое возвращает SessionFactory.GetCurrentSession() (используя ThreadContext текущий сеансовый провайдер, так что это сеанс за потоком) или через DI (инъекция зависимостей - снова с использованием ThreadContext.)
Дополнительная информация о GetCurrentSession и контекстных сеансах здесь.
Ответ 3
Я согласен, примеров для приложений с поддержкой состояния не так много.
Я собираюсь сделать следующее:
Как и у вас, у меня есть служба Windows, обслуживающая несколько служб WCF. Таким образом, службы WCF являются точками входа.
В конечном итоге все мои службы WCF наследуют от AbstractService - который обрабатывает много протоколирования и базовые вставки/обновления БД.
В одном из лучших сообщений NHibernate, которые я видел, HttpModule делает следующее:
см. http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx
private void BeginTransaction(object sender, EventArgs e) {
NHibernateSessionManager.Instance.BeginTransaction();
}
private void CommitAndCloseSession(object sender, EventArgs e) {
try {
NHibernateSessionManager.Instance.CommitTransaction();
}
finally {
NHibernateSessionManager.Instance.CloseSession();
}
}
Поэтому, возможно, я должен сделать что-то подобное в AbstractService. Таким образом, я получаю сессию за вызов службы. Если вы изучите ссылку на статью NHib передовой практики выше, вы увидите, что NHibernateSessionManager должен иметь дело со всем остальным, если я открываю и закрываю сеанс (конструктор и дескриптор AbstractService).
Просто мысль. Но я испытываю ошибки, потому что моя сессия, кажется, слишком долго висит вокруг, и я получаю печально известную ошибку - NHibernate.AssertionFailure: нулевой идентификатор в записи (не очищайте сеанс после возникновения исключения).
Ответ 4
Вы также можете очистить сеанс, не закрывая его, и он выполняет одно и то же. Я делаю.
Ответ 5
Недавно мы начали использовать контейнер IoC для управления жизненным циклом сеанса в качестве замены упомянутых выше контекстных сессий. (Подробнее здесь).