Ссылки на объекты Java со слоем кэша - PullRequest
5 голосов
/ 07 января 2010

Мы создали слой кэширования для нашего J2EE-приложения. В этом случае мы используем Ehcache. Это создало несколько проблем.

Давайте возьмем этот пример.

OrderItem orderitem = cache.getOrderItemByID("id");
OrderItem old_orderitem = cache.getOrderItemID("id");

orderitem.setStatus(1);
old_orderitem.setStatus(2);

Если мы не будем осторожны, любые изменения, внесенные в один из этих объектов, будут влиять на другой (они ссылаются на один и тот же объект). Сохранение элемента заказа обратно в базу данных даст ему статус = 2

Как бы мы решили это наилучшим образом?

Мы попытались создать метод .copyObject () для каждого объекта. Который просто создает новый объект и устанавливает все значения. Но это не похоже на хорошее решение.

Пример был только для иллюстрации. Код гораздо сложнее, но результат тот же.

********************** Обновление 15.07.2010 ********************* *****************************

В EHCache 2 есть несколько опций, чтобы включить copyRead () и copyWrite (). И это решает все мои проблемы:)

Ответы [ 4 ]

5 голосов
/ 07 января 2010

Это проблема с изменяемым состоянием. Это не только кэширование, но в любое время вы можете иметь несколько ссылок на один и тот же объект, и этот объект является изменяемым. Например:

HashMap map = new HashMap();
map.put("one", new OrderItem());
OrderItem one = map.get("one");
OrderItem two = map.get("one");
one.setStatus(1);
two.setStatus(2);

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

Вы правы, подумав о копировании объекта. Ваши варианты:

У каждого есть свои сильные и слабые стороны, и то, какой из них работает лучше всего, зависит от вашей среды.

1 голос
/ 07 января 2010

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

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

0 голосов
/ 21 июля 2011

Ehcache предоставляет поддержку для блокировки ключей через явный API блокировки. Вы можете заблокировать ключ в кеше с помощью блокировки чтения и записи. Это не блокирует значение в кеше, поэтому объект по-прежнему открыт для мутации, если так решит программист.

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

Однако проблема изменчивого состояния, как упоминает Джейми МакКриндл, не исчезает.

Ссылка: http://ehcache.org/documentation/explicitlocking.html

0 голосов
/ 07 января 2010

Когда вы извлекаете данные из кэша по id (getOrderItemById), я предполагаю, что это означает «получить объект , уникально идентифицированный по id =?». Во втором отрывке у вас есть (или вы пытаетесь иметь?) 2 разных объекта, поэтому похоже, что вы пытаетесь сделать 2 противоречивые вещи в коде.

Вы можете применить уникальность-Id = "ID" всегда один и тот же объект. Если вы устанавливаете статус, а затем сбрасываете его, это означает, что тот же объект имеет новый статус. Возможно, вы захотите расширить метод .equals, чтобы он возвращал true, если идентификатор также совпадает.

Вы также можете использовать «грязный» флаг, чтобы пометить объекты, которые были изменены из (транзакционного?) Хранилища данных.

Создание копии тоже неплохой способ справиться с этим, хотя неясно, что значит иметь 2 объекта, бегающих с одинаковым идентификатором. Может быть, копия должна быть создана с нулевым идентификатором, чтобы указать, что она еще не существует в кэше?

Какое поведение подходит для вашего приложения?

...