Управление сеансом с использованием 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.
- Как получить поток GUI, отделенный от задней части.
Я рекомендую хранить объекты спящего режима строго на обратной стороне, из которой они происходят. Предоставлять только объекты обертки для ETD. Если этим объектам-оболочкам задано значение, они создают запрос, который передается в backend-поток, который в конечном итоге вернет значение.
Я бы представил три вида обертки:
Async: запрашивает значение и получает уведомление, когда это значение доступно. Он немедленно вернется с некоторой фиктивной ценностью. При уведомлении он активирует событие PropertyChange i.O. информировать GUI о "измененном" значении (измененном от неизвестного до реального значения).
Синхронизировать: запрашивает значение и ожидает его доступности.
Timed: смесь между ними, ожидая короткого времени (0,01) секунды, перед возвратом. Это позволит избежать много изменений событий по сравнению с асинхронной версией.
В качестве основы для этих оболочек рекомендуется ValueModel библиотеки JGoodies Binding: http://www.jgoodies.com/downloads/libraries.html
Очевидно, что вам нужно позаботиться о том, чтобы любое действие выполнялось только для фактически загруженных значений, но поскольку вы не планируете делать обновления, это не должно быть проблемой.
Позвольте мне закончить с предупреждением: я много думал об этом, но никогда не пробовал, поэтому двигайтесь с осторожностью.