# Сессия приложения Сессия приложения создается на поток прикладной бизнес логики и предоставляет доступ к сессии базы данных, EclipseLink кэшу, серверу приложения. А так же содержит необходимые инъекции зависимости для работы прикладной бизнес логики. Сессия приложения создается: - на каждую mdi форму открытую в приложении - на rest запрос к серверу приложения ```{note} Для ускорение rest запросов возможна настройка пула сессий ``` Сессия приложения не привязана к сессии базы данных. Сессия базы данных выделяется на запрос либо на транзакцию. Каждый контроллер прикладной бизнес логики содержит контекст сессии который представляет из себя фасад для быстрого доступа к сессии приложения и стандартным языковым примитивам фреймворка. ## Сессия базы данных Физическое соединение с базой. Фреймворк использует механизм коротких транзакций в БД. Сессия БД выделяется для получения или изменения данных и возвращается в пул после окончания работы с данными. Число прикладных сессий не равно числу соединений с БД. Сессия базы данных выделяется из пула при: - Начале транзакции - Выполнении запроса из прикладного кода. ## Рабочее пространство (workspace) Рабочее пространство содержит транзакционный кэш чтения, а так же перечень изменений для отправки в базу данных. Рабочее пространство создается при любом действии с базой данных. Чтение, создание\удаление\обновление. И удаляется при commit или rollback. ### Точки сохранения При создании точки сохранения, происходит сброс всех изменений из рабочего пространства в базу данных. При откате к точке сохранения, рабочее пространство удаляется. ## Пользовательский сеанс Пользовательский сеанс начинается в момент открытия формы в новой сессии, и заканчивается при закрытии формы. ```{note} При открытии модального окна в той же сессии, пользовательские блокировки работают в сеансе дочерней формы. ``` Пользовательские сеансы можно просмотреть: `Меню приложения > помощь > блокировки` ## Пользовательская блокировка Пользовательская блокировка позволяет блокировать бизнес-объект вне транзакции базы данных. Такая блокировка работает в разрезе пользовательского сеанса. Элементы заблокированного бизнес-объекта не могут быть изменены каким-либо другим пользовательским сеансом. Пользовательскую блокировку можно снять, при этом все заблокированные сессией объекты становятся доступны для блокирования. Подробнее можно почитать [здесь](http://helpcenter.gs.local/btk_documentaion_v1/html/120_%D0%9F%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B0%D1%8F%20%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0.html). ## Логические блокировки Логические блокировки являются транзакционными, и снимаются на commit или rollback. Для получения блокировки используется метод `Btk_LogicLockPkg.request()`, в который передается имя блокировки. Сессия при получении блокировки будет ожидать фиксацию или откат данных другой сессии, которая уже получила эту блокировку до этого. ## Оптимистические блокировки По умолчанию класс использует оптимистическую блокировку, для этого в таблице создается служебное поле `nVersion_dz`. В случае, если версия загруженного в транзакционный кэш перед изменением объекта отличается от версии в строке таблицы базы данных при сохранении изменений, возникает ошибка сохранения. Преимущества оптимистической блокировки: - Не требует начало транзакции базы данных Недостатки оптимистической блокировки: - Ошибка проявляется только при сохранении изменений в базу \ В момент возникновения ошибки, сложнее отловить ее источник. - Возможно появления лишней нагрузки на базу данных \ От момента правки строки, до момента возникновение ошибки может пройти существенный набор действий который в итоге будет откачен. ## Пессимистическая блокировка Транзакционная блокировка с помощью которой можно заблокировать строку базы данных. При необходимости данная блокировка может быть выполнена с помощью: - [ATSql запроса](055_взаимодействие_с_базой.md/#atsql) ```{tip} Смотрите [Явные блокировки](https://postgrespro.ru/docs/postgrespro/14/explicit-locking) ``` - [OQuery](055_взаимодействие_с_базой.md/#объектные-запросы) c опцией `forUpdate` - `Btk_Pkg().lockObjects` Преимущества пессимистической блокировки - Конфликт определяется в момент выполнения блокировки Недостатки пессимистической блокировки: - Требует транзакции базы данных ## Бизнес логика На каждый контроллер бизнес логики создается объект в контексте сессии приложения. Таким образом бизнес логика работает в контексте сессии что позволяет: - Хранить переменные объекта в разрезе сессии - Выполнять объектные запросы в базу данных с учетом сессионного кэша - Работать в контексте транзакции сессии ### Ключевые стратегии создания масштабируемого решения 1. Минимизируйте количество запросов к базе данных \ Для этого используйте: - bulk загрузку кэша - транзакционные индексы - разделяемые классы - кэширование запросов для разделяемых классов 2. Ограничивайте размер транзакции \ Для этого: - разбивайте бизнес логику на части \ К примеру разбейте массив бизнес объектов на порции для обработки. - Используйте `commitwork` \ Это позволяет сбросить данные в базу без завершения транзакции, при этом происходит очистка оперативной памяти. ### Api Содержит бизнес логику по обработке данных в таблице класса(сущности). Каждому классу соответствуют два файла с кодом бизнес логики данного класса: - `Xxx_XxxxDpi` \ Содержит авто формируемый прикладной код. Данный код пересоздаётся системой формирования кода и не должен меняться разработчиками - `Xxx_XxxxApi` \ Содержит прикладной код, изменяемый разработчиками #### Пример API ```scala 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 Пакеты создаются разработчиками по необходимости. Пакеты содержат методы бизнес-логики, которые не возможно отнести к какому-либо классу. ```scala class Xxx_XxxxPkg extends Pkg{} object Xxx_XxxxPkg extends PkgFactory[Xxx_XxxxPkg] ```