Управление сеансом 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 для управления жизненным циклом сеанса в качестве замены упомянутых выше контекстных сессий. (Подробнее здесь).