带有缓存层的Java对象引用

时间:2010-01-07 17:21:18

标签: java object reference pass-by-reference pass-by-value

我们已经为J2EE应用程序创建了一个缓存层。在这个例子中,我们使用Ehcache。这带来了一些挑战。

我们来看这个例子。

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

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

如果我们不小心,对这两个对象所做的任何更改都会影响另一个对象(它们引用同一个对象)。将orderitem保存回dabase将使其具有status = 2

我们如何以最佳方式解决这个问题?

我们尝试为每个对象创建一个.copyObject()方法。这只是创建一个新对象并设置所有值。但这似乎不是一个好的解决方案。

这个例子只是为了说明。代码远比那复杂,但结果是一样的。

**********************更新于2010年7月15日********************* *********

在EHCache 2中,有一些选项可以打开copyRead()和copyWrite()。这解决了我所有的问题:)

4 个答案:

答案 0 :(得分:5)

这是一个可变状态的问题。它不仅是缓存,而且任何时候你都可以对同一个对象进行多次引用,并且该对象是可变的。例如:

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 :(得分:1)

听起来您想要缓存表示对象的数据(例如,数据库查询的结果)而不是对象本身(例如,您可能想要在其他地方检索的用户的会话数据)。 / p>

如果是这种情况,你的自定义缓存层(在ehcache周围)需要在用户发出请求时从缓存数据中创建一个对象 - 这样每次都会给你一个唯一的对象而你不会受到对象干扰

答案 2 :(得分:0)

当您通过id(getOrderItemById)从缓存中检索时,我认为这意味着“获取由id =?标识的对象唯一”。在你的第二个摘录中你有(或者试图拥有?)2个不同的对象,所以它看起来有点像你在代码中尝试做两个相互矛盾的事情。

您可以强制执行唯一性-Id =“ID”始终是同一个对象。如果设置状态然后重置它,则表示同一对象具有新状态。如果id匹配,您可能希望扩展.equals方法以返回true。

您还可以使用“脏”标记来标记从(事务性?)数据存储中更改的对象。

制作副本也不是解决这个问题的坏方法,尽管不清楚让2个对象以相同的id运行是什么意思。也许副本应该用空id创建,以表明它在缓存中不存在?

您的申请的正确行为是什么?

答案 3 :(得分:0)

Ehcache通过显式锁定API提供对锁定键的支持。您可以使用读写锁定锁定缓存中的密钥。这不会锁定缓存中的值,因此如果程序员决定,该对象仍然可以突变。

这可能会也可能不会解决您提到的问题,具体取决于您的看法。如果程序员愿意遵守纪律,并且仅将读取的对象用于读取目的,并且在获取了对象上具有写锁定的对象时修改+更新缓存,那么这应该可行。

然而,正如Jamie mccrindle所提到的那样,可变状态问题并没有消失。

参考:http://ehcache.org/documentation/explicitlocking.html