Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to turn off hibernate version increment for particular update?

Tags:

hibernate

jpa

Is it possible update entity in database without modifying version of entity using hibernate?

Using my web application users can create or update entities. And where is another asynchronous process which “processes” these entities after any user operation. If user opens entity for update before entity is “processed”, but tries to save it after it is “processed”, user will get “OptimisticLockException” and all his entered data will be lost. But I would like to overwrite data updated in asynchronous process with user provided data.

code snipet to demonstrate why I need such behaviour (JPA + Hibernate):

//user creates entity by filling form in web application
Entity entity = new Entity ();
entity.setValue("some value");
entity.setProcessed (false);
em.persist(entity);
em.flush();
em.clear();

//but after short period of time user changes his mind and again opens entity for update
entity = em.find(Entity.class, entity.getId());
em.clear(); //em.clear just for test purposes

//another application asynchronously updates entities 
List entities = em.createQuery(
                "select e from Entity e where e.processed = false")
                .getResultList();
for (Object o: entities){
    Entity entityDb = (Entity)o;
    someTimeConsumingProcessingOfEntityFields(entityDb); //update lots of diferent entity fields
    entityDb.setProcessed(true);
    em.persist(entityDb);
}        
em.flush(); //version of all processed entities are incremented.       
//Is it possible to prevent version increment?
em.clear();  

//user modifies entity in web application and again press "save" button
em.merge(entity); //em.merge just for test purposes
entity.setValue("some other value");
entity.setProcessed (false);
em.persist(entityDb);
em.flush(); //OptimisticLockException will occur.        
//Is it possible to prevent this exception from happening?
//I would like to overwrite data updated in asynchronous process 
//with user provided data.

And my entity:

@Entity
@Table(name = "enities")
public class Entity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Version
    private int versionNum;
    @Column
    private String value
    @Column
    private boolean processed;
    //… and so on (lots other properties)
}

In reality I have much more classes with similar problem - so I am looking for some elegant non intrusive solution.

It seems to me this is quite usual scenario. But I could not find any information how to achieve such functionality.

like image 246
Palladium Avatar asked Nov 28 '15 14:11

Palladium


People also ask

How update method works in hibernate?

update() method updates the entity for persistence using the identifier of detached object or new instance of entity created with existing identifier. If the object is already in the session with the same identifier, then it throws exception.

How does hibernate versioning work?

When ever we use versioning then hibernate inserts version number as zero, when ever object is saved for the first time in the database. Next time when we update this object, hibernate increments that version no by one automatically . In hibernate mapping file, add an element called version soon after id element.

Can we update primary key in hibernate?

No. Hibernate doesn't allow to change the primary key.

What is update in hibernate?

update Update method in the hibernate is used for updating the object using identifier. If the identifier is missing or doesn't exist, it will throw exception. saveOrUpdate This method calls save() or update() based on the operation.


1 Answers

Hibernate Optimistic Locking can be bypassed using hibernate Session (http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/Session.html) replicate(...) method.

Example of code which does not increment version:

//Detaching to prevent hibernate to spot dirty fields. 
//Otherwise if entity exists in hibernate session replication will be skipped 
//and on flush entity will be updated with version increment.
em.detach(entityDb); 
someTimeConsumingProcessingOfEntityFields(entityDb);  

//Telling hibernate to save without any version modifications.
//Update hapends only if no newer version exists.
//Executes additional query DB to get current version of entity.
hibernateSession.replicate(entity, ReplicationMode.LATEST_VERSION);

I think this solution is better than native SQL update, because:

  • ORM mappings (anotations or *.hbm.xml) are uses (no need to duplicate Java objects <-> DB Tables mapping in native queries);
  • no need to manually execute flush (performance);
  • db and hibernate caches are in same state, no need to evict entities form cache (perfomance);
  • and you still have all ORM provided features like optimistic locking, and so on... ;
like image 158
Palladium Avatar answered Sep 17 '22 13:09

Palladium