Search This Blog

Tuesday 5 June 2012

Hibernate And Bulk Operations -1

We have often executed SQL queries of the type:
update <table> set <record_column> = <value> where <condition>;
These kind of queries that results in multiple records being updated are termed bulk updates.Hibernate allows us to do the same too. Consider the below code that updates the name column of all Entity records
static void testBulkUpdate() {
    Session session = sessionFactory.openSession();
    Transaction transaction = null;
    try {
        transaction = session.beginTransaction();
        Entity entity = (Entity) session.load(Entity.class, 3L);
        System.out.println("Entity name is " + entity.getName());
        System.out.println("Updating all entity  names ");
        Query query = session.createQuery("update Entity e set e.name = :newName");
        query.setString("newName", "UNKNOWN");
        query.executeUpdate();
        transaction.commit();
        System.out.println("Name of Entity with id " + entity.getId() 
                + " is " + entity.getName() );
        session.close();
    } catch (Exception e) {
        e.printStackTrace();
        transaction.rollback();
        
    }
}
As seen in the above code the update query is written in HQL and executed Hibernate's Query Interface.The logs indicate the output of the code:
2406 [main] DEBUG org.hibernate.SQL  - 
    select
        entity0_.ID as ID0_0_,
        entity0_.NAME as NAME0_0_ 
    from
        ENTITY entity0_ 
    where
        entity0_.ID=?
Entity name is Simple Name
Updating all entity  names 
2812 [main] DEBUG org.hibernate.engine.query.HQLQueryPlan  - HQL param location 
recognition took 15 mills (update Entity e set e.name = :newName)
2937 [main] DEBUG org.hibernate.engine.query.HQLQueryPlan  - executeUpdate: upda
te Entity e set e.name = :newName
2937 [main] DEBUG org.hibernate.SQL  - 
    update
        ENTITY 
    set
        NAME=?
2953 [main] DEBUG org.hibernate.impl.SessionImpl  - after transaction completion
Name of Entity with id 3 is Simple Name
As can be seen a select query was executed initially which returns the entity with id 3 and displays the name property. After that the update query executes and this should update the name column for all records with value "UNKNOWN". After successful query execution we checked the value in persistent object Entity with id 3. However there is an anomaly here. The entity continues to display the name as Simple Name.
Did our update query fail ?
Or was the record with id 3 skipped as it was associated with a hibernate session ?
I decided to check the output in the database:
records in table after the update code
The query executed fine and updated all the records (including 3). So why does the persistent object continue to display the old data?
If we execute an SQL statement directly on the database then the statement result does not affect any objects in the persistence cache. Hibernate is not aware that Entity with id 3 has changed in the database. Hence it does update it and the entity continues to hold stale data.
Possible solutions to the problem would be:
  1. call session.refresh(entity) method. This would reload the row from the database. But then we would need to know precisely which row was affected.
  2. Execute all such bulk operations in the beginning of the session, ensuring that the persistence cache has no objects in it that could get affected by the update call.

No comments:

Post a Comment