问题
Suppose I have an entity defined as follows:
@Entity
public class MyEntity {
@Id
@GeneratedValue
private Integer id;
@Column
private String name;
@Version
int version;
// Getters + setters
}
Suppose also I have a service (REST API or something similar) that allows a user to retrieve information about this entity. It returns the ID, the current name, and the current version. There is also another service that allows a user to update the name of an entity. It accepts the ID, update name, and version as input parameters. So the entity could be updated by creating a new object and using a merge:
public MyEntity update(EntityManager em, int id, String name, int version) {
MyEntity entity = new Entity();
entity.setId(id);
entity.setName(name);
entity.setVersion(version);
return em.merge(entity);
}
Alternatively it could be updated by retrieving it from the database and updating the relevant fields only:
public MyEntity update(EntityManager em, int id, String name, int version) {
MyEntity entity = em.find(MyEntity.class, id);
entity.setName(name);
entity.setVersion(version);
return entity;
}
My testing tells me that in Hibernate 5.3 the first scenario will throw an OptimisticLockException (with the message Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
) if the provided version does not match what is in the database. However, the second scenario works fine and the name is updated regardless of the version supplied.
I have also tried this with DataNucleus 5.1.9 and there neither scenario throws an exception and the name is updated regardless of the version supplied in both cases.
So I guess either there is a bug in Hibernate or DataNucleus, one of them is not following the JPA specification, or the specification doesn't clearly specify how this should work?
I have tried to find a definitive answer to this but was unable to do so. Can someone confirm how, according to the JPA specification, should optimistic locking work when it comes to updating entities with a version number supplied externally?
回答1:
Eeeek, externally setting the @Version field? This would probably lead in most cases to conflicts, as it is not supposed to be set by the developer. It is managed by the Persistence Provider, exclusively. You won't need a getter
nor a setter
to access the version
.
An excerpt from the JPA 2.0 spec:
The Version field or property is used by the persistence provider to perform optimistic locking. It is accessed and/or set by the persistence provider in the course of performing lifecycle operations on the entity instance. An entity is automatically enabled for optimistic locking if it has a property or field mapped with a Version mapping. An entity may access the state of its version field or property or export a method for use by the application to access the version, but must not modify the version value[34]. With the exception noted in section 4.10, only the persistence provider is permitted to set or update the value of the version attribute in the object.
Regarding your update process: You typically retrieve the ID of your object and the data you want to change from your Rest Interface. You pass both to a Service
, in which you tell your EntityManager
to fetch the entity with the given ID, update the data on that entity, and tell the EntityManager
to save it back right away. This procedure is not carved in stone, but roughly that's how it's done in most cases.
Both, the setID()
and setVersion()
methods on your entites are very likely to be bad practice.
来源:https://stackoverflow.com/questions/50420000/does-the-jpa-optimistic-locking-specification-support-validating-against-a-versi