具有缓存层的 Java 对象引用
我们已经为 J2EE 应用程序创建了一个缓存层。在本例中我们使用 Ehcache。这带来了一些挑战。
我们以这个例子为例。
OrderItem orderitem = cache.getOrderItemByID("id");
OrderItem old_orderitem = cache.getOrderItemID("id");
orderitem.setStatus(1);
old_orderitem.setStatus(2);
如果我们不小心,对其中一个对象所做的任何更改都会影响另一个对象(它们引用同一个对象)。将 orderitem 保存回数据库将使其状态=2
我们如何以最佳方式解决这个问题?
我们尝试为每个对象创建一个 .copyObject() 方法。它只是创建一个新对象并设置所有值。但这似乎不是一个好的解决方案。
这个例子只是为了说明。代码比这复杂得多,但结果是一样的。
**********************更新 2010 年 7 月 15 日 ************************ **************************
在 EHCache 2 中,有一些选项可以打开 copyRead() 和 copyWrite()。这解决了我所有的问题:)
We've created a caching layer to our J2EE-application. In this instance we use Ehcache. This has created a few challenges.
Let's take this example.
OrderItem orderitem = cache.getOrderItemByID("id");
OrderItem old_orderitem = cache.getOrderItemID("id");
orderitem.setStatus(1);
old_orderitem.setStatus(2);
If we're not carefull, any changes made to either of those objects will affect the other (they reference the same object). Saving orderitem back to the dabase would make it have status=2
How would we solve this the best way?
We've tried making a .copyObject() method to each object. Which just creates a new object and sets all the values. But this doesn't seem like a good solution.
The example was just to illustrate. The code is far more complex than that, but the result is the same.
**********************Update 15.07.2010 **************************************************
In EHCache 2 there are some options to to turn on copyRead() and copyWrite(). And this solves all my problems :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是可变状态的问题。它不仅仅是缓存,任何时候您都可以对同一对象有多个引用,并且该对象是可变的。例如:
会遇到完全相同的问题。当您有并发环境时,这会变得更加复杂。解决这个问题的一种方法是只使用不可变的对象。这样,如果你想要一个具有不同状态的对象,你就必须创建一个新的。它还使并发编程变得更容易。
您考虑复制该对象是正确的。您的选项是:
每种方法都有其优点和缺点,哪一种最有效取决于您的环境。
This is a problem with mutable state. It isn't only caching, it's any time you could have multiple references to the same object and that object is mutable. For example:
Will have exactly the same problem. This becomes even more complicated when you have a concurrent environment. One way to solve this is to only have immutable objects. That way, if you want an object with different state, you're going to have to make a new one. It also makes concurrent programming easier.
You're right to consider copying the object. Your options are:
Each has their strengths and weaknesses and which one works best will depend on your environment.
听起来您想要缓存表示对象的数据(例如,数据库查询的结果)而不是对象本身(例如,您可能想在其他地方检索的用户的会话数据)。
如果是这种情况,您的自定义缓存层(围绕 ehcache)需要在用户发出请求时从缓存数据创建一个对象 - 这将为您每次提供一个唯一的对象,并且您不会受到对象干扰。
It sounds like you want to cache the data representing an object (for example, the results of a database query) rather than an object itself (for example, session data for a user that you may want to retrieve elsewhere).
If this is the case, your custom cacheing layer (around ehcache) needs to create an object from the cache data when a user makes a request - this will give you a unique object every time and you won't get object interference.
当您通过 id (getOrderItemById) 从缓存中检索时,我认为这意味着“获取由 id=? 唯一标识的对象”。在你的第二个摘录中,你有(或试图拥有?)2个不同的对象,所以看起来有点像你试图在代码中做两件相互矛盾的事情。
您可以强制 uniqueness-Id="ID" 始终是同一对象。如果设置状态然后重置它,则意味着同一对象具有新的状态。您可能希望扩展 .equals 方法,以便在 id 也匹配时返回 true。
您还可以使用“脏”标志来标记已从(事务性?)数据存储中更改的对象。
制作一个副本也不是处理这个问题的好方法,尽管尚不清楚让 2 个对象以相同的 id 运行意味着什么。也许应该使用 null id 创建副本以表明它尚不存在于缓存中?
对于您的应用程序来说,什么是正确的行为?
When you retrieve from the cache by id (getOrderItemById) I'd assume that to mean "get the object uniquely identified by id=?". In your second excerpt you have (or are trying to have?) 2 different objects so it looks a bit like you're trying to do 2 contradictory things in the code.
You could enforce uniqueness-Id="ID" is always the same object. If you set the status and then reset it, it means the same object has new status. You'd probably want to extend the .equals method to return true if the id matches as well.
You could also use a "dirty" flag to mark objects that have been changed from the (transactional?) data store.
Making a copy is not a bad way to deal with this either, though it's not clear what it means to have 2 objects running around with the same id. Maybe the copy should be created with a null id to indicate that it doesn't exist in the cache yet?
What's the right behavior for your application?
Ehcache 通过显式锁定 API 提供对锁定密钥的支持。您可以使用读锁和写锁来锁定缓存中的键。这不会锁定缓存中的值,因此如果程序员决定,该对象仍然可以进行更改。
这可能会也可能不会解决您提到的问题,具体取决于您如何看待它。如果程序员愿意遵守纪律,并且仅将读取获取的对象用于读取目的,并在获取的对象在键上具有写锁时修改+更新缓存,那么这应该可行。
然而,正如杰米·麦克林德尔提到的,可变状态问题并没有消失。
参考:http://ehcache.org/documentation/explicitlocking.html
Ehcache provide support for locking keys via an explicit locking API. You can lock on the key in the cache with read and write locks. This does not lock on the value in the cache, so the object is still open to mutation if the programmer so decides.
This may or may not solve the problem you mention, depending on how you see it. If the programmer is wiling to be disciplined, and uses read acquired objects only for read purposes, and modify + update cache when acquired objects with write lock on the key, then this should work.
However, the mutable state problem, as jamie mccrindle mentions, does not go away.
Reference: http://ehcache.org/documentation/explicitlocking.html