Как сохранить согласованность кэша Hibernate при запуске двух приложений Java? - PullRequest
8 голосов
/ 08 сентября 2008

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

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

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

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

Любые мысли о том, есть ли что-то принципиально неправильное в этом дизайне, или если кто-то делает это и ему повезло с работой с hibernate на перезагрузках.

Спасибо, Chris

Ответы [ 4 ]

11 голосов
/ 08 сентября 2008

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

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

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

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

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

3 голосов
/ 08 сентября 2008

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

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

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

2 голосов
/ 22 февраля 2009

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

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

1 голос
/ 27 ноября 2012

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

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

Пояс и подтяжки :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...