Управление сеансом с использованием Hibernate в * многопоточном * Swing приложении

В настоящее время я работаю над (довольно большим) домашним проектом моего любимца, приложение Swing, которым он должен быть очень многопоточным. Почти все пользовательские взаимодействия могут извлекать данные с некоторых удаленных серверов через Интернет, поскольку я не контролирую эти серверы и сам Интернет, поэтому длительное время ответа неизбежно. Пользовательский интерфейс Swing явно не может перерисовываться, пока EDT занят, поэтому все удаленные серверные вызовы должны выполняться фоновыми потоками.

Моя проблема:

Данные, получаемые фоновыми потоками, становятся "обогащенными" данными из локальной (в памяти) базы данных (удаленный сервер возвращает идентификаторы/ссылки на данные в локальной базе данных). Эти данные позже передаются в EDT, где они становятся частью модели представления. В этот момент некоторые объекты не полностью инициализированы (включена ленивая выборка), поэтому пользователь может инициировать ленивую выборку, например. прокрутка в JTable. Поскольку сеанс hibernate уже закрыт, это вызовет исключение LazyInitializationException. Я не знаю, когда пользователь может вызвать ленивую выборку, поэтому создание сеанса по требованию/прикрепление отдельного объекта здесь не будет работать.

Я решил эту проблему:

  • с использованием одного (синхронизированного, так как экземпляры сеанса не являются потокобезопасными) Сессия для всего приложения
  • отключить ленивый выбор.

В то время как это работает, производительность приложения сильно пострадала (иногда близкая к непригодной для использования). Замедление в основном вызвано большим количеством объектов, которые теперь извлекаются каждым запросом.

В настоящее время я думаю об изменении дизайна приложения на "Session-per-thread" и переносе всех объектов, полученных из потоков, отличных от EDT, в сеанс потока EDT (аналогично это сообщение на форумах Hibernate).

Боковое примечание. Любые проблемы, связанные с обновлениями базы данных, не применяются, поскольку все объекты базы данных доступны только для чтения (справочные данные).

Любые другие идеи о том, как использовать Hibernate с ленивой загрузкой в ​​этом сценарии?

Ответ 1

Не подвергайте сам сеанс в API данных. Вы можете сделать это лениво, просто убедитесь, что гидратация выполняется из потока 'каждый раз. Вы можете использовать блок (runnable или какой-то командный класс, вероятно, лучшая Java может сделать для вас здесь, к сожалению), которая завершена кодом, который выполняет асинхронную загрузку из потока данных. Когда вы используете код UI (конечно, в потоке пользовательского интерфейса), какое-то событие "данные готовы", которое отправляется службой данных. Затем вы можете получить данные из использования события в пользовательском интерфейсе.

Ответ 2

Вы могли бы взглянуть на Ebean ORM. Работает без сеанса, и ленивая загрузка просто работает. Это не отвечает на ваш вопрос, но действительно предлагает альтернативу.

Я знаю, что Ebean построила поддержку для асинхронного выполнения запросов, что также может быть интересно для вашего сценария.

Возможно, стоит посмотреть.

  • Роб.

Ответ 3

Есть две различные проблемы, которые должны решаться отдельно:

Основная идея состоит в том, чтобы иметь сеанс для каждого фрейма, исключая модальные кадры, которые используют сеанс кадра нереста. Это непросто, но это работает. Значит, вы больше не получите LLE.

  1. Как получить поток GUI, отделенный от задней части.

Я рекомендую хранить объекты спящего режима строго на обратной стороне, из которой они происходят. Предоставлять только объекты обертки для ETD. Если этим объектам-оболочкам задано значение, они создают запрос, который передается в backend-поток, который в конечном итоге вернет значение.

Я бы представил три вида обертки:

Async: запрашивает значение и получает уведомление, когда это значение доступно. Он немедленно вернется с некоторой фиктивной ценностью. При уведомлении он активирует событие PropertyChange i.O. информировать GUI о "измененном" значении (измененном от неизвестного до реального значения).

Синхронизировать: запрашивает значение и ожидает его доступности.

Timed: смесь между ними, ожидая короткого времени (0,01) секунды, перед возвратом. Это позволит избежать много изменений событий по сравнению с асинхронной версией.

В качестве основы для этих оболочек рекомендуется ValueModel библиотеки JGoodies Binding: http://www.jgoodies.com/downloads/libraries.html

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

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