DTO and JPA Version

dtohibernatejava-eejpa

I have DB tables representing Employees and Departments. The server side(JavaEE) contains JPA entities representing the same.

The client is a standalone client and communicates with the server using DTOs. In my case, a single DTO contains both the Employee and Dept details.

I want to implement Optimistic locking using the Version annotation on these entities, but there is an issue: When the client send the DTO with the updated values to the server method(webservice), the server method creates entities using the values in the DTO and then it finds the entity using the find() method on JPA and then calls update(). There is not much gap between find() and update().

But the issue is that the value coming from the DTO itself might be stale. Since I am using standalone client, I do not have the context of the server's JPA entities. JPA itself cannot find that the value is old (because the version between find() and update() matches) and overwrites the entity with stale data. Is there a way to solve this issue?

Best Answer

Optimistic locking using version numbers is based on the principle that you know which version of the data was retrieved from the database before making any modifications, so that you can verify that no intermediate updates have taken place between your retrieval of an entity and writing your changes back.

For this to work, the version number must be an integral part of the entity (and must only be changed by the database). This means that the version number must also be communicated in your DTO to the client, preferably as a read-only attribute.

If the version number is part of the DTO, then you can detect stale data in two ways:

  1. The find method checks the version number against the current version of the entity and reports "entity version mismatch" when the two don't match.
  2. The update method fails if the version of the entity doesn't match the version number in the database. To avoid race conditions, this check should always be performed, even if the find function also checks the version number.

If you did detect stale data, you can react in several ways:

  1. Report an error and let the user refresh the entity and re-enter his changes
  2. Report the conflict to the user and let him merge his changes into the new version of the entity (showing what was changed externally and what was changed by the user).
  3. Try to perform an automated merge, and if that doesn't work fall back to 2 (for example if multiple edits were made to the same field).
Related Topic