具有缓存层的Java对象引用

具有缓存层的Java对象引用,java,object,reference,pass-by-reference,pass-by-value,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); 如果我们不小心,对其中一个对象所做的任何更改都会影响另一个对象(它们

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

让我们举个例子

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

orderitem.setStatus(1);
old_orderitem.setStatus(2);
如果我们不小心,对其中一个对象所做的任何更改都会影响另一个对象(它们引用同一个对象)。将orderitem保存回数据库将使其状态为2

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

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

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

**********************更新15.07.2010**************************************************


在Ehcache2中,有一些选项可以启用copyRead()和copyWrite()。这就解决了我的所有问题:)

这听起来像是要缓存表示对象的数据(例如,数据库查询的结果),而不是对象本身(例如,您可能希望在别处检索的用户的会话数据)


如果是这种情况,当用户发出请求时,您的自定义缓存层(围绕ehcache)需要从缓存数据创建一个对象-这将每次为您提供一个唯一的对象,并且您不会受到对象干扰。

当您通过id(getOrderItemById)从缓存中检索时,我假定这是指“获取id=?”唯一标识的对象。在第二篇摘录中,您有(或正在尝试有?)两个不同的对象,因此看起来有点像您试图在代码中做两件相互矛盾的事情

如果Id=“Id”始终是同一个对象,则可以强制执行唯一性。如果设置状态并将其重置,则表示同一对象具有新状态。如果Id匹配,则可能需要扩展.equals方法以返回true

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

创建副本也不是一种很好的处理方法,尽管不清楚两个对象以相同的id运行意味着什么。也许应该使用空id创建副本,以表明它在缓存中还不存在


您的应用程序的正确行为是什么?

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

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);
将有完全相同的问题。当您有一个并发环境时,这将变得更加复杂。解决这一问题的一种方法是只拥有不可变的对象。这样,如果您想要一个具有不同状态的对象,则必须创建一个新的对象。这也使并发编程更容易

你考虑复制对象是对的。你的选择是:

  • 通过复制构造函数进行深度复制

每种方法都有各自的优缺点,哪种方法最有效取决于您的环境。

Ehcache通过显式锁定API提供对锁定密钥的支持。您可以使用读写锁锁定缓存中的密钥。这不会锁定缓存中的值,因此如果程序员这样做,对象仍然会发生变异退伍军人

这可能会解决您提到的问题,也可能不会解决,这取决于您如何看待它。如果程序员希望遵守规则,并且仅将读取获取的对象用于读取目的,并且在获取对象时修改并更新缓存,并且密钥上带有写锁,那么这应该会起作用

然而,正如杰米·麦克林德尔所提到的,可变状态问题并没有消失


参考:

如果它们在逻辑上都是相同的顺序,为什么不希望对一个对象的更改影响另一个?如果两个顺序对象都保留在同一个DB记录中,那么其中一个将覆盖另一个。正如我所说的,这比这个简单的示例要复杂一些。例如,当我更新OrderItem时,我希望将旧的OrderItem保存到另一个表具有不同的状态,而新表具有另一个状态。是的,这就是我试图做到的。在将对象存储到内存缓存之前,是否应该克隆()该对象?如果该对象是可变的,则选择“是”,并将克隆的对象存储在内存缓存中