Перейти к основному содержанию
`Ctrl`+`K`

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

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

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

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

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

  Примечание

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Примечание

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- ATSql запроса

  Совет

  Смотрите Явные блокировки

- OQuery c опцией `forUpdate`

- `Btk_Pkg().lockObjects`

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

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

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

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

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

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

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

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

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

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

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]