Сессия приложения#

Сессия приложения создается на поток прикладной бизнес логики и предоставляет доступ к сессии базы данных, EclipseLink кэшу, серверу приложения. А так же содержит необходимые инъекции зависимости для работы прикладной бизнес логики.

Сессия приложения создается:

  • на каждую mdi форму открытую в приложении

  • на rest запрос к серверу приложения

    Примечание

    Для ускорения rest запросов возможна настройка пула сессий

Сессия приложения не привязана к сессии базы данных. Сессия базы данных выделяется на запрос либо на транзакцию.

Каждый контроллер прикладной бизнес логики содержит контекст сессии который представляет из себя фасад для быстрого доступа к сессии приложения и стандартным языковым примитивам фреймворка.

Сессия базы данных#

Физическое соединение с базой.

Фреймворк использует механизм коротких транзакций в БД. Сессия БД выделяется для получения или изменения данных и возвращается в пул после окончания работы с данными.

Число прикладных сессий не равно числу соединений с БД.

Сессия базы данных выделяется из пула при:

  • Начале транзакции

  • Выполнении запроса из прикладного кода.

Рабочее пространство (workspace)#

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

Рабочее пространство создается при любом действии с базой данных. Чтение, создание\удаление\обновление. И удаляется при commit или rollback.

Точки сохранения#

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

Пользовательский сеанс#

Пользовательский сеанс начинается в момент открытия формы в новой сессии, и заканчивается при закрытии формы.

Примечание

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

Пользовательские сеансы можно просмотреть: Меню приложения > помощь > блокировки

Завершение сессий из прикладного кода#

В разделе описывается завершение рабочей сессии и сессии приложения.

Рабочая сессия представляет работу пользователя на сервере приложений. Она регистрируется на узле кластера и определяется идентификатором sid. Для завершения рабочей сессии из прикладного кода используется Btk_WorkSessionPkg#killSession().

Сессия приложения — это контекст выполнения прикладной бизнес-логики. Такая сессия создаётся, например, для открытой MDI-формы или REST-запроса и предоставляет прикладному коду доступ к данным, транзакции и сервисам приложения. Для её закрытия используются Session#close() и SessionUtils#closeSession().

При использовании описанных ниже методов активная транзакция всегда завершается: изменения фиксируются или откатываются.

Закрытие рабочей сессии#

Btk_WorkSessionPkg#killSession()

Метод завершает выбранную рабочую сессию. Сессия определяется по узлу кластера и идентификатору sid.

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

Btk_WorkSessionPkg().killSession(clusterNode, sid)

где:

  • clusterNode — имя узла кластера, на котором открыта рабочая сессия;

  • sid — идентификатор завершаемой рабочей сессии.

Для массового завершения сессий сформируйте список имён пользователей, получите их активные рабочие сессии и вызовите killSession() для каждой найденной сессии:

val savUser = <список имён пользователей, сессии которых нужно закрыть>

val targetSessions = Btk_WorkSessionPkg()
  .getWorkingSessionByCluster(true)
  .filter(s =>
    s.user.isNotNullOrEmpty && savUser.contains(s.user)
  )

targetSessions.foreach { session =>
  Btk_WorkSessionPkg().killSession(session.clusterNode, session.sid)
}

В примере завершаются все рабочие сессии пользователей, имена которых содержатся в savUser.

Закрытие сессии приложения#

ru.bitec.app.gtk.eclipse.Session#close()

Метод предназначен для закрытия текущей сессии приложения из прикладного кода. Это прикладная версия CoreSession#close().

При вызове метода сессия закрывается, связанные с ней ресурсы освобождаются, а сама сессия дерегистрируется из JdbcContext рабочего сеанса. JdbcContext используется для отслеживания JDBC-соединений, выделенных для формы, рабочей сессии и GTK-сессии.

Активная транзакция при закрытии сессии всегда завершается. Метод не принимает параметров для явного выбора между фиксацией и откатом транзакции.

SessionUtils#closeSession()

Метод является обёрткой над ru.bitec.app.gtk.eclipse.Session#close(). Перед закрытием сессии он выполняет фиксацию или откат транзакции, после чего вызывает ru.bitec.app.gtk.eclipse.Session#close().

При вызове без параметра commit выполняется откат транзакции:

SessionUtils.closeSession(session)

Для фиксации транзакции перед закрытием передайте commit = true:

SessionUtils.closeSession(session, commit = true)

Сессия закрывается и при ошибке фиксации или отката транзакции. Возникшее исключение передаётся вызывающему коду.

Пользовательская блокировка#

Пользовательская блокировка позволяет блокировать бизнес-объект вне транзакции базы данных. Такая блокировка работает в разрезе пользовательского сеанса. Элементы заблокированного бизнес-объекта не могут быть изменены каким-либо другим пользовательским сеансом.

Пользовательскую блокировку можно снять, при этом все заблокированные сессией объекты становятся доступны для блокирования.

Подробнее можно почитать здесь.

Логические блокировки#

Логические блокировки являются транзакционными, и снимаются на commit или rollback.

Для получения блокировки используется метод Btk_LogicLockPkg.request(), в который передается имя блокировки.

Сессия при получении блокировки будет ожидать фиксацию или откат данных другой сессии, которая уже получила эту блокировку до этого.

Оптимистические блокировки#

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

Преимущества оптимистической блокировки:

  • Не требует начало транзакции базы данных

Недостатки оптимистической блокировки:

  • Ошибка проявляется только при сохранении изменений в базу
    В момент возникновения ошибки, сложнее отловить ее источник.

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

Пессимистическая блокировка#

Транзакционная блокировка с помощью которой можно заблокировать строку базы данных. При необходимости данная блокировка может быть выполнена с помощью:

Преимущества пессимистической блокировки

  • Конфликт определяется в момент выполнения блокировки

Недостатки пессимистической блокировки:

  • Требует транзакции базы данных

Бизнес логика#

На каждый контроллер бизнес логики создается объект в контексте сессии приложения. Таким образом бизнес логика работает в контексте сессии что позволяет:

  • Хранить переменные объекта в разрезе сессии

  • Выполнять объектные запросы в базу данных с учетом сессионного кэша

  • Работать в контексте транзакции сессии

Ключевые стратегии создания масштабируемого решения#

  1. Минимизируйте количество запросов к базе данных
    Для этого используйте:

    • bulk загрузку кэша

    • транзакционные индексы

    • разделяемые классы

    • кэширование запросов для разделяемых классов

  2. Ограничивайте размер транзакции
    Для этого:

    • разбивайте бизнес логику на части
      К примеру разбейте массив бизнес объектов на порции для обработки.

    • Используйте commitwork
      Это позволяет сбросить данные в базу без завершения транзакции, при этом происходит очистка оперативной памяти.

Api#

Содержит бизнес логику по обработке данных в таблице класса(сущности). Каждому классу соответствуют два файла с кодом бизнес логики данного класса:

  • Xxx_XxxxDpi
    Содержит авто формируемый прикладной код. Данный код пересоздаётся системой формирования кода и не должен меняться разработчиками

  • Xxx_XxxxApi
    Содержит прикладной код, изменяемый разработчиками

Пример API#

class Bs_GdsCostDeviationTypeApi extends Bs_GdsCostDeviationTypeDpi[Bs_GdsCostDeviationTypeAro, Bs_GdsCostDeviationTypeApi, Bs_GdsCostDeviationTypeAta] {
  override protected def entityAta: Bs_GdsCostDeviationTypeAta = Bs_GdsCostDeviationTypeAta

  def register(spCode: NString
               , spCaption: NString
               , spDescription: NString): Unit = {
    val ropSelf = get(findByMnemoCode(spCode)).getOrElse {
      insert() :/ { rop =>
        setsCode(rop, spCode)

        rop
      }
    }

    setsCaption(ropSelf, spCaption)
    setsDescription(ropSelf, spDescription)
  }
}

Pkg#

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

class Xxx_XxxxPkg extends Pkg{}  
object Xxx_XxxxPkg extends PkgFactory[Xxx_XxxxPkg]