| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java EE (J2EE) и Spring > Hibernate, доступ к базе с нескольких приложений |
| Автор: pnd_ku 28.4.2009, 14:46 |
| Здраствуйте! Мне нужно создать приложение на Java+Hibernate, но существует проблема: может быть запущенно несколько инстансов этого приложения и тогда будет иметь место борьба за данные. В моём случае - это книга назначений пациентов. То есть 4 таблицы: врачи, пациенты, рабочие времена и назначения. Как организовать data concurrency? Спасибо! |
| Автор: garbuz 28.4.2009, 17:18 |
| Посмотрите паттерн синглтон. |
| Автор: tux 28.4.2009, 18:09 |
| Data concurrency можно организовать используя средства Hibernate. Например, он поддерживает версионность объектов, то есть умеет автоматически проставлять версии для сохраняемых объектов. Если сравнить версию редактируемого объекта с версией объекта, который сейчас в базе можно предпринять какие-то действия - загрузить данные из базы еще раз и попросить пользователя ввести заново или сделать еще что-то. В документации помнится все достаточно подробно было описано, примерно здесь - http://hibernate.org/hib_docs/v3/reference/en/html/transactions.html. Сайт у них с сожалению сейчас не работает. |
| Автор: pnd_ku 28.4.2009, 19:20 | ||||
| to garbuz: одиночка в данной ситуации - не решение проблемы, а уход от неё to tux: документация у них шыкааарная - тут не поспориш 1) по теме. В документации к сожалению не описано как версионность регулируется. Да, там есть упоминание что это сделано таймстампами. Но версия объекта хранится в базе или в сессии? Соответственно если версия отслеживается средставами БД, то вопрос решён. Если же средствами хибернейт, то 2 разных хибернейт сессии не узнают о изменении версии объекта другой сессией. Всё-таки в базе или в прослойке хибернейта? 2)чуть чуть не по теме. Флоу странности такой: - выборка коллекции из базы по условиям... у нас появляется объект List, которые содержит выбранные сущности - изменение одной из записей в базе непосредственно - выборка коллекции по тем же условиям... по логам видно что запрос прошол, но свойства изменнённого объекта не обновились! решение было такое - вызывать метод evict, чтобы сбросить кеш.. кажется мне - это странное решение, не элегантное.. почему же хибернейт не обновляет свойства изменённого объекта, ведь новые данные о нём он получил? ах да, такая странность заметна только когда запрашиваю List, если делаю load одного объекта - всё в порядке Поясню на примере логов хибернейта Ожыдаем такое: делаем запрос
List availableSlots; изменяем один из availableSlots не из текущей сессии повторяем запрос
List availableSlots должен содержать коллекцию с одним обновлённым слотом но этого не происходит!!! |
| Автор: pnd_ku 28.4.2009, 22:29 | ||||
4 разные машины, 4 запущщеных приложения с общими данными на сервере.. я что-то не очень понимаю при чом здесь синглтон |
| Автор: garbuz 28.4.2009, 22:50 | ||
Так, теперь кажется я вас понял, у вас не клиент-сервер приложение, вся логика находится на стороне клиента, у каждого запущен отдельный инстанс приложения. Верно я вас понимаю? |
| Автор: pnd_ku 28.4.2009, 23:26 |
| Общий сервер БД. И куча инстансов (все одинаковые) приложения. Все одинаковые. Всё таки клиент-сервер, но клиентов много. Почти всё верно! |
| Автор: tux 29.4.2009, 06:17 | ||||
В базе. И это не обязательно timestamp, можно использовать тэг <version> и простой integer, который будет автоматически инкрементироваться при сохранении объекта. Например, вот такой простой класс и маппинг:
Хотя в общем-то и в реализации на уровне движка Hibernate не видно каких-то проблем. Ведь не обязательно хранить две копии одного и того же объекта для двух разных сессий. Впрочем, реально Hibernate хранит в кэше копии объекта в каждой сессии, где к нему обращались. По пункту 2. По всей видимости ты данные в базе менял в момент активности сессии. Пока активна сессия, Hibernate кэширует все объекты, с которыми работает, поэтому и не подгружает объект. Загружать конкретные объекты тоже не должен, если конечно не пытаешься новый объект с тем же идентификатором создать. В принципе я понимаю почему у тебя проблемы - видимо сессия открывается один раз и потом не закрывается. Так делать не рекомендуется, обычно сессия открывается на один запрос. Вот надо тебе получить список слотов и показать на экране - открываешь сессию, загружаешь что нужно, показываешь и закрываешь сессию. Поведение Hibernate в этом случае вполне логично - что если пользователь захочет изменить один и тот же объект несколько раз? Не выполнять же столько же запросов к базе. |
| Автор: pnd_ku 29.4.2009, 06:35 |
| 1) вау! 2 переопределённых метода и изменения в маппинге - класс! в офф документации я этого не увидел, хотя прочитал всю в оригинале. великолепно! с хранением версии объекта в бд теперь всё исчерпывающе понятно, спасибо Вам огромное! 2)да, одна сессия на всё приложение. тут кстати в документации тоже конфликт. с одной стороны сессия-на-приложение - антипаттерн, но и с другой - сессия-на-запрос тоже. Тут дело такое, что мы отдетачели объект, а его оригинал в базе может быть изменён сторонним приложением и при апдейте его допустим нужно иметь свежайшую версию. Поэтому одна сессия на всё приложение. Хотя при некритичных ХиебрнейтЭксшепшнах все изменения откатываюца (в пределах одного ворк-юнита) и сессия пересоздаёца, чтобы избежать конфликтов и подгрузить заново все объекты. Возможно Вы правы, и стоит рассмотреть вариант с сессией на запрос, но это чревато бОльшими расходами на работу с БД ибо выборка реально не маленькая и часто повторяющаяся. А в целом Вы многое прояснили, премного благодарен! Теперь моя работа с хибернейтом станет ещё комфортнее |