5

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

2
  • 2
    If they're both logically the same Order, why do you NOT want changes to one object to affect the other? If both Order objects persist to the same DB record, one of them would overwrite the other anyways. Commented Jan 7, 2010 at 17:27
  • As I said, its a bit more complex than this simple example. Like when I update an OrderItem I want to save the old OrderItem to another table with a different status, and the new one with another status. Commented Jan 7, 2010 at 21:23

4 Answers 4

6

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:

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

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.

Sign up to request clarification or add additional context in comments.

2 Comments

so, should one clone() the object before storing it in an in-memory cache?
If it's mutable? Then yes and store the cloned object in the in-memory cache
1

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.

1 Comment

Yes, thats's what Im trying to do
0

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?

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.