带有缓存层的 Java 对象引用

Posted

技术标签:

【中文标题】带有缓存层的 Java 对象引用【英文标题】:Java object references with cache layer 【发布时间】:2011-01-02 14:12:57 【问题描述】:

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

让我们举这个例子。

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

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

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

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

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

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

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

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

【问题讨论】:

如果它们在逻辑上是相同的订单,为什么你不希望对一个对象的更改影响另一个?如果两个 Order 对象都保存在同一个数据库记录中,那么其中一个无论如何都会覆盖另一个。 正如我所说,它比这个简单的例子要复杂一些。就像我更新 OrderItem 时一样,我想将旧的 OrderItem 保存到另一个具有不同状态的表中,而新的则具有另一种状态。 【参考方案1】:

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

这可能会也可能不会解决您提到的问题,这取决于您如何看待它。如果程序员愿意自律,将读取获取的对象仅用于读取目的,并在获取对象时修改+更新缓存,并在键上写锁,那么这应该可以。

但是,正如 jamie mccrindle 所提到的,可变状态问题并没有消失。

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

【讨论】:

【参考方案2】:

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

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);

会有完全相同的问题。当您有一个并发环境时,这变得更加复杂。解决此问题的一种方法是仅具有不可变对象。这样,如果您想要一个具有不同状态的对象,您将不得不创建一个新对象。它还使并发编程更容易。

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

Cloning Deep copying via serialization 通过复制构造函数进行深度复制

每个人都有自己的长处和短处,哪一种效果最好取决于您的环境。

【讨论】:

那么,是否应该在将对象存储在内存缓存中之前对其进行克隆()? 如果它是可变的?然后是的,并将克隆的对象存储在内存缓存中【参考方案3】:

当您通过 id (getOrderItemById) 从缓存中检索时,我假设这意味着“获取由 id=? 标识的对象唯一”。在您的第二段摘录中,您拥有(或正在尝试拥有?)2 个不同的对象,因此看起来您正试图在代码中执行 2 个相互矛盾的事情。

您可以强制执行唯一性-Id="ID" 始终是同一个对象。如果你设置了状态然后重置它,这意味着同一个对象有新的状态。如果 id 也匹配,您可能希望扩展 .equals 方法以返回 true。

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

制作副本也不是解决此问题的坏方法,尽管尚不清楚让 2 个具有相同 ID 的对象到处运行意味着什么。也许应该使用空 id 创建副本以指示它不存在于缓存中?

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

是的,这就是我想做的事情

以上是关于带有缓存层的 Java 对象引用的主要内容,如果未能解决你的问题,请参考以下文章

01 对象的引用关系 VS 缓存

java对象四种引用原理

4中引用(强,软,弱,虚)侧重弱引用

java的四种引用,强弱软虚

如何将json字符串转成带有对象引用的java对象

java 强弱软虚 四种引用,以及用到的场景