Как обеспечить согласованность кэша Hibernate при запуске двух приложений Java?

StackOverflow https://stackoverflow.com/questions/48733

  •  09-06-2019
  •  | 
  •  

Вопрос

В нашем проекте есть одна jvm, представляющая собой jboss/webapp (чтение/запись), которая используется для хранения данных в спящем режиме (с использованием jpa) в базе данных.Модель имеет 10-15 постоянных классов с 3-5 уровнями глубины отношений.

Затем у нас есть отдельная JVM, которая является сервером, использующим эти данные.Поскольку он работает постоянно, у нас есть только один длинный сеанс базы данных (только чтение).

В настоящее время внутренний кэш JVM не используется, поэтому мы вручную сигнализируем одну JVM из другой.

Теперь, когда веб-приложение меняет некоторые данные, оно сигнализирует серверу о необходимости перезагрузить измененные данные.Мы обнаружили, что нам нужно указать спящему режиму очистить данные, а затем перезагрузить их.Простое выполнение выборки/слияния с БД не дает результата - в основном в отношении объектов, находящихся на нескольких уровнях ниже по иерархии.

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

Спасибо, Крис

Это было полезно?

Решение

Сеанс Hibernate загружает все данные, которые он считывает из БД, в то, что они называют кэш первого уровня.После загрузки строки из БД любые последующие выборки строки с тем же PK будут возвращать данные из этого кэша.Более того, Hibernate гарантирует равенство ссылок для объектов с одинаковым PK в одном сеансе.

Насколько я понимаю, ваше серверное приложение только для чтения никогда не закрывает сеанс Hibernate.Поэтому, когда БД обновляется приложением для чтения и записи, сеанс на сервере только для чтения не знает об изменении.По сути, ваше приложение только для чтения загружает копию базы данных в памяти и использует эту копию, которая со временем устаревает.

Самый простой и лучший способ действий, который я могу предложить, — это закрывать и открывать сеансы по мере необходимости.Это обходит всю проблему.Сеансы Hibernate предназначены для кратковременного взаимодействия с БД.Я согласен, что производительность повышается, если не перезагружать объектный граф снова и снова;но вам нужно измерить это и убедить себя, что оно того стоит.

Другой вариант — периодически закрывать и снова открывать сеанс.Это гарантирует, что приложение, доступное только для чтения, будет работать с данными не старше заданного интервала времени.Но определенно существует окно, в котором приложение, доступное только для чтения, работает с устаревшими данными (хотя конструкция гарантирует, что оно в конечном итоге получит актуальные данные).Во многих приложениях это допустимо — вам нужно оценить свою ситуацию.

Третий вариант – использовать кэш второго уровня реализацию и использовать кратковременные сеансы.Существуют различные пакеты кэширования, работающие с Hibernate, имеющие определенные преимущества и недостатки.

Другие советы

Крис, я немного озадачен твоими обстоятельствами.Если я правильно понимаю, у вас есть как веб-приложение (чтение/запись), так и автономное приложение (только для чтения?), использующее Hibernate для доступа к общей базе данных.Изменения, которые вы вносите в веб-приложение, не видны в автономном приложении.Это правильно?

Если да, рассматривали ли вы возможность использования другой реализации кэша второго уровня?Мне интересно, сможете ли вы использовать кластерный кеш, который используется как веб-приложением, так и автономным приложением.Я считаю, что SwarmCache, интегрированный с Hibernate, позволит это, но сам я этого не пробовал.

Однако в целом вы должны знать, что содержимое данного кеша никогда не будет знать об активности другого приложения (вот почему я предлагаю, чтобы оба приложения использовали общий кеш).Удачи!

С моей точки зрения, вам следует изменить свой подчеркнутый кеш Hibernate на тот, который поддерживает кластерный режим.Это может быть Кэш JBoss или Роевой тайник.Первый имеет лучшую поддержку синхронизации данных (репликация и аннулирование), а также поддерживает JTA.

Затем вы сможете настроить синхронизацию кеша между веб-приложением и сервером.Также обратите внимание на уровень изоляции, если вы будете использовать JBoss Cache.Я считаю, что вам следует использовать ЧТЕНИЕ_КОММИТЕД режим, если вы хотите получить новые данные на сервере из того же сеанса.

Наиболее распространенной практикой является наличие Менеджер объектов, управляемых контейнером чтобы два или более приложений в одном контейнере (например, Glassfish, Tomcat, Websphere) могли использовать одни и те же кэши.Но если вы не используете контейнер приложения, поскольку используете Play!например, тогда я бы создал несколько веб-сервисов в основное приложение для последовательного чтения/записи в кеше.

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

Ремень и подтяжки :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top