Versioned id’s

If you are using multiple system transactions that span a single business transaction, there is chance of isolation problems: a business transaction could see changes made by other transactions and this could lead to erroneous behavior.

Example:
there is a web page that can be accessed by management, that contains a list of all employees. Each row contains the id, the name, the date of the last bonus and a button to give the bonus. When the button is pressed, the id of the employee (eventually) is send to the following service method:

@Transactional
void giveBonus(long id){
	//load throws a special exception if the employee is not found
	//Spring: ObjectRetrievalFailureException if employee isn't found
	Employee e = employeeDao.load(id);
	e.giveBonus();
}

The problem with this approach is that 2 managers could access the page at roughly the same moment and both see that some employee didn’t get a bonus for some time and decide to give the bonus. The consequence is that the employee has received the bonus twice. Although this example is a little bit hypothetical, in some cases this behavior could lead to serious problems.

Optimistic locking is one of the best known techniques to deal with these issues: it doesn’t lock (unlike pessimistic locking) but hopes (is optimistic) about the fact that no other transaction is going to conflict. If a different transaction does make a change, the version of the data is changed, and this is something that can be checked. As soon as a difference between versions is found, an optimistic locking failure exception can be thrown.

Just carrying around the version and id, doesn’t feel that good. It makes method signatures less pretty and you have to carry it around. Especially when you need to deal with multiple entities, the solution gets more ugly. The solution is simple: integrate id and version into a single structure: VersionedId. VersionedId’s contain the id of an entity and also contain the version of that entity; so a VersionedId can uniquely identify an entity in time and could look like this:

class VersionedId{
	long version, id;
}

the previous example could be rewritten by using a VersionedId:

@Transactional
void giveBonus(VersionedId id){
	//load throws a special exception if the employee is not found or version doesn't match
	//Spring: ObjectRetrievalFailureException if employee not found
	//Spring: OptimisticLockingFailureException if version doesn't match
	Employee e = employeeDao.load(id);
	e.giveBonus();
}

As you can see there is not much difference. But you have to make sure that the load method of the EmployeeDao is able to handle versioned id’s and starts throwing some kind of optimistic locking failure if the Employee with the given id and version can’t be found. And instead of just placing the id of the employee on the html-page, the version needs to be placed as well.

Using detached objects (and reattaching them) is also a solution. But there are some issues:

  1. The detached objects need to be stored and the most likely place is the HttpSession. This could lead to replication issues if you are in a clustered environment
  2. Vague transactional behavior
  3. I have seen some weird issues with detaching and reattaching entities with Hibernate (especially not detaching completely)
Advertisements

3 Responses to Versioned id’s

  1. Sam says:

    In JPA you can add a simple @Version annotation to a version field to get optimistic locking for such situations. If you use Hibernate you can even do this without declaring the field and set the annotation on the @Entity itself… but I tend to avoid non-JPA solutions. The second commit will result in an exception when the thread attempts to commit the transaction.

    I’m not 100% sure what the advantages of your approach are over this?

  2. pveentjer says:

    Hi Sam, thanks for your reply.

    The versioned id’s don’t replace optimistic locking (the @version tag in your case). But if you don’t have/want a reference to the entity, but only the id, you are not able to do optimistic locking. If you add the version to the id, you can do optimistic locking.

    So the versioned id is an alternative to detached entities (and both rely on optimistic locking). It is just another tool in the toolbox.

  3. Sam says:

    Ok, I see what you’re doing now… kinda. I think 🙂

    Are you suggesting that VersionedId be an @Embeddable @Id ? I’m not sure I like that… it means you’re just moving the version column from the @Entity into an @Embeddable… which means it would still be a part of the same table. Doesn’t changing IDs also have all kinds of strange side effects? It would also mean you have to provide the ID and versioning in Java land.

    Or are you using VersionedId as an intermediary class to allow access to some methods? So I get my persistent object, create the VersionedId and then use that as the parameter to the DAO? But that would mean you have to do a version comparison at some point, and I thought JPA would do that automatically anyway if @Version was set within a table.

    Perhaps I’m mixing up my understanding of JPA in J2SE with the Spring way of doing things (I’ve never used Spring before and frankly it confuses me what it actually does!). I’m guessing @Transactional means that it is part of a “conversation” (i.e. quite a long Transaction) and there are no transaction commits allowed in the method (or anything that would result in an emmediate write to the database). Could you tell me what the full classname of @Transactional is, please?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: