Sandeep Chauhan

Thursday 24 July 2014

Hibernate Locking(with version and time stamp)

The <version> property (or @Version annotation)

For those of you that use Hibernate today, you are probably aware that Hibernate can provide optimistic locking through a version property on your persistent objects.  Furthermore, the version property is automatically managed by Hibernate.
To specify a version for your persistent object, simply add a version (or timestamp) property in your mapping file and add a version attribute to your persistent class.  Here is an example on a Product class.
public class Product {
    private long id;
    private String name;
    private String model;
    private double cost;
    private long version;

}
<hibernate-mapping package=”com.intertech.domain”>
  <class name=”Product”>
          <id name=”id”>
            <generator class=”native” />
        </id>
        <version name=”version” type=”long” />
        <property name=”name” not-null=”true” />
        <property name=”model” not-null=”true” />
        <property name=”cost” type=”double”/>
  </class>
</hibernate-mapping>
For those using annotations, just mark the version property’s getter in the class with the @Version annotation.
@Version public long getVersion() {
    return version;
}
The version property on the class can be numeric (short, int, or long) or timestamp or calendar.  However, another configuration element is provided for timestamps or calendars (covered below).
With automatic versioning (and version set to a numeric), Hibernate will use the version number to check that the row has not been updated since the last time it was retrieved when updating the persistent object (Product in this example).  Notice the extra where “and version = X” clause below, when a product from above is updated.
Hibernate:
    /* update
        com.java.Product */ update
            Product
        set
            version=?,
            name=?,
            model=?,
            cost=?
        where
            id=?
            and version=?
If the version has been updated, Hibernate throws a StaleObjectStateException and the transaction (and any persistent object changes) rollback.  If the update commits without issue, Hibernate also increments the version number automatically (note the “set version = ?” as part of the update clause above).

Hibernate versus the Database Managing the Version

Under this configuration and in this example, Hibernate (from within your Java application) is managing the version number.  However, some DBA’s may prefer to have the version controlled by database rather than Hibernate, especially when the database may be a timestamp and the application is distributed to multiple systems (maybe even timezones).  If the Hibernate application is on different systems that are not time synchronized, the timestamp generated by each system might be different thereby generating improper optimistic lock success or failures.  To inform Hibernate to have the database manage the version, include a generated=”always” attribute in the Hibernate mapping of the persistent object.
<hibernate-mapping package=”com.java.domain”>
  <class name=”Product”>
          <id name=”id”>
            <generator class=”native” />
        </id>
        <version name=”version” type=”long” generated=”always”/>
        <property name=”name” not-null=”true” />
        <property name=”model” not-null=”true” />
        <property name=”cost” type=”double”/>
  </class>
</hibernate-mapping>
Hibernate will now defer to the database to generate the necessary version and update the persistent object’s row accordingly.  A warning is in order however.  This will cause Hibernate to issue an extra SQL to get the version number back from the database after a successful update or insert.  Note the extra SQL issued below after a successful update of a product (Hibernate even comments it to indicate why it is needed).  You might also note that the version number is not set as above when updating the product.  Again, Hibernate is now totally deferring to the database to manage this property.
Of important note, not all dialects (i.e. databases) support the managing of the version number.  HSQLDB, for example, does not allow the version number to be controlled from the database.
Hibernate:
    /* update
        com.java.domain.Product */ update
            Product
        set
            name=?,
            model=?,
            cost=?
        where
            id=?
            and version=?
Hibernate:
    /* get generated state com.java.domain.Product */ select
        product_.version as version8_
    from
        Product product_
    where
        product_.id=?

Timestamps for Version

In many situations, your DBA or organization may prefer a timestamp to be used as the version indicator.  In theory, the timestamp is a little less safe than a version number.  This is because a timestamp can, in theory, be updated by two transactions at the exact same time (depends on the precision of the database) and allow both to update causing a last in wins scenario (violating the optimistic lock).  It can also be argued that timestamps also take up more space in the database.  Depending on the dialect, the use of a timestamp may incur an additional hit of the database to get the timestamp.  However, on the plus side, timestamps provide useful information about the “when” a row was last altered.  In cases of auditing or record tracking, this might be important information.  Version numbers don’t provide any context for when an update occurred.
If a timestamp is useful, change your version property to be a java.util.Date or Calendar and use a <timestamp> (rather than using a <version>) element in the mapping file.
public class Product {

    private Date version;

}
<hibernate-mapping package=”com.java.domain”>
  <class name=”Product”>
          <id name=”id”>
            <generator class=”native” />
        </id>
        <!–<version name=”version” type=”timestamp” generated=”always”/>–>
        <timestamp name=”version” source=”db”/>         <property name=”name” not-null=”true” />
        <property name=”model” not-null=”true” />
        <property name=”cost” type=”double”/>
   </class>
</hibernate-mapping>
The <version type=timestamp”> and <timestamp> are equivalent, but it might help the reader to better see/understand that the version is an effectivity timestamp versus a numerical indicator.
You might also notice the source=”db” in the mapping configuration above.  The source attribute can be set to “vm” (for virtual machine) or “db” (for database).  When set to “db”, the database creates and manages the version timestamp (equivalent to generated=”always”) above.  As mentioned above, in the case of the database managing the version timestamp, your application may incur an additional hit of the database as Hibernate must first retrieve the timestamp before updating the row.  Further, as the Hibernate documentation says:  “Not all Dialects are known to support the retrieval of the database’s current timestamp.”

Optimistic Locking without a Version

Your application may need to deal with a legacy database and the database cannot be altered to contain a version (numeric or timestamp) column.  In this case, Hibernate provides two additional options for optimistic lock management.  You can use all the fields of the persistent object to check that nothing in a row was modified before updating a row.  Set the optimistic-lock=”all” attribute (and dynamic-update=”true”) in the <class> element to use this approach.  The SQL issued by Hibernate will then use each property as a check in the where clause as shown below.
Hibernate:
    /* update
        com.java.domain.Product */ update
            Product
        set
            name=?
        where
            id=?
            and name=?
            and model=?
            and cost=?
comparison of the state of all fields in a row but without a version or timestamp property mapping, turn on optimistic-lock="all" in the <class> mapping
As a slight alternative to this approach, you can set optimistic-lock=”dirty” and then Hibernate will only use modified columns as part of the optimistic check (see below).  This last approach actually allows to transactions to update the same object concurrently legally, but only if they are modifying different columns – something that might be advantageous in a larger application setting where many people are accessing the same objects (thus rows) but rarely updating the same properties (columns).
Hibernate:
    /* update
        com.intertech.domain.Product */ update
            Product
        set
            name=?
        where
            id=?
            and name=?
See the Hibernate documentation for more details on these alternatives to versioning.

Hibernate Locking

Hibernate Optimistic Locking

The question I would like to address in this post is about Hibernate optimistic locking, optimistic locking with no special version number or timestamp.  While pessimistic locking is an available option in Hibernate to address concurrency control, for most enterprise applications, optimistic locking is the preferred choice.  As the Hibernate documentation states:
The only approach that is consistent with high concurrency and high scalability, is optimistic concurrency control with versioning”
Hibernate can provide optimistic locking via version number or effectivity timestamp.  To learn more about either approach, you can see an earlier post of mine, or check out the Hibernate documentation.   Optimistic locking via version number or effectivity timestamp is automatically managed by Hibernate.  Simply provide the column to hold the version or timestamp, add the optimistic lock characteristics to your Hibernate mapping (via XML or annotations), and Hibernate does the rest.

Optimistic Locking sans Version or Timestamp

However, there may be situations whereby adding a version number or timestamp column to your database table is not possible.  This might be the case when a legacy database is in place and many applications use the table and cannot or will not be updated to use a new version/timestamp column for optimistic locking.  In this case, Hibernate can compare the column values of a table row against the state of the persistent object to check that nothing in a row was modified before updating the row.  There are two forms of this state-checking optimistic locking:  all-state-check or dirty-state-check.

Optimistic-lock = ‘all’

When you set the optimistic-lock attribute on the <class> element in the Hibernate mapping file to the value ‘all’ (as shown on the Vehicle class mapping below), you are informing Hibernate to check that no column in the associated row has changed since the persistent object was retrieved and before updating the row in the database.
   1: <hibernate-mapping package="com.intertech.domain">
   2:     <class name="Vehicle" dynamic-update="true" optimistic-lock="all">
   3:         <id name="id">
   4:             <generator class="increment" />
   5:         </id>
   6:         <property name="make" />
   7:         <property name="model" />
   8:         <property name="vin" />
   9:     </class>
  10: </hibernate-mapping>
For example, say you used Hibernate to obtain an instance of Vehicle and then updated it’s make as shown by the code below.
   1: SessionFactory sf = new Configuration().configure()
   2:         .buildSessionFactory();
   3: Session sess = sf.openSession();
   4: Transaction trx = sess.beginTransaction();
   5: Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
   6: v.setMake("ford");
   7: sess.saveOrUpdate(v);
   8: trx.commit();
   9: sess.close();
Hibernate would actually use all the existing persistent object values (the last known state values) to form the SQL where-clause used in the update call.  Note that every column is mentioned in the where-clause of the example, even the old value of the changed property (make in this case).  If any other concurrent activity on this row changed the data of the row (or deleted the row), Hibernate would detect this by the fact that the where-clause would fail to match the row (resulting in a StaleObjectStateException.
   1: Hibernate:
   2:     update
   3:         Vehicle
   4:     set
   5:         make='Kia'
   6:     where
   7:         id=1
   8:         and make='Ford'
   9:         and model='SUV'
  10:         and vin=12345

Optimistic-lock = ‘dirty’

As an alternative, you can also allow Hibernate to only use modified or dirty properties in the where-clause of the update.  When mapping the persistent class, set the optimistic-lock attribute to a value of ‘dirty’ (as shown below).
   1: <hibernate-mapping package="com.intertech.domain">
   2:     <class name="Vehicle" dynamic-update="true" optimistic-lock="dirty">
   3:         <id name="id">
   4:             <generator class="increment" />
   5:         </id>
   6:         <property name="make" />
   7:         <property name="model" />
   8:         <property name="vin" />
   9:     </class>
  10: </hibernate-mapping>
Hibernate now uses only the last known state values of modified persistent object properties to form the SQL where-clause used in the update call.  As an example, assume this code is used to update a Vehicle’s make and model state.
   1: SessionFactory sf = new Configuration().configure()
   2:         .buildSessionFactory();
   3: Session sess = sf.openSession();
   4: Transaction trx = sess.beginTransaction();
   5: Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
   6: v.setMake("Chevy");
   7: v.setModel("sedan");
   8: sess.saveOrUpdate(v);
   9: trx.commit();
  10: sess.close();
The update SQL only includes checks of the existing row’s make and model columns, that is the dirty properties.
   1: Hibernate:
   2:     update
   3:         Vehicle
   4:     set
   5:         make='Chevy',
   6:         model='sedan'
   7:     where
   8:         id=1
   9:         and make='Kia'
  10:         and model='SUV'
This alternative allows other concurrent processes to update the same row so long as they do not modify the same columns.  For example, another application could be updating the vin number of our vehicle at the same time we are updating the make and model and neither of the applications suffer a concurrency error.  The merits of allowing this type of simultaneous update are questionable (at best).  From a business perspective, only you can determine if modifications that do not conflict constitute change that should cause a concurrency failure or not.  Hibernate provides the options, you must determine whether the technology fits with your definition of protecting against concurrent change issues.

Dynamic-update must be True

It should be noted that in both of these non-version/timestamp optimistic locking options, you must enable dynamic-update (set the dynamic-update=’true’ attribute) in the class mapping as shown above.  This is because Hibernate cannot generate the SQL for these update statements at application startup (it wouldn’t know what to include in the update statement where-clauses until a change is actually made).

Big Limitations of Non-Version/Timestamp Optimistic Locking

Regardless of whether you use the optimistic-lock=all or optimistic-lock=dirty strategy, there are some big limitations to Hibernate’s optimistic locking that does not use version numbers or timestamps.

No Detached

When you close a session, Hibernate loses its persistence context and ability to track what changes on the objects.  Therefore, you cannot use the optimistic-lock=all or optimistic-lock=dirty option unless you retrieve and modify the persistent object in the same session (i.e. persistence context).  If you attempt to get a persistent object in one session, detach the object and then update the object in another session, you will actually create a situation of potentially catastrophic last-in-wins updates.  For example, try this code with optimistic-lock set to ‘all’ on the Vehicle class mapping.
   1: SessionFactory sf = new Configuration().configure()
   2:         .buildSessionFactory();
   3: Session sess = sf.openSession();
   4: Transaction trx = sess.beginTransaction();
   5: Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
   6: trx.commit();
   7: sess.close();
   8: System.out.println("vehicle now detached: " + v);
   9:
  10: v.setVin(7890);
  11:
  12: //reattach and update
  13: sess = sf.openSession();
  14: trx = sess.beginTransaction();
  15: sess.saveOrUpdate(v);
  16: trx.commit();
  17: sess.close();
  18: System.out.println("vehicle saved again: " + v);
When Hibernate reattaches the Vehicle object and brings it back into the persistence context in the second session, it actually does the unthinkable, it synchronizes (i.e. updates) every column of the associated row without checking to see if it was updated by some other concurrent process!  Last in wins and no concurrency check!!!
   1: Hibernate:
   2:     update
   3:         Vehicle
   4:     set
   5:         make='Chevy',
   6:         model='sedan',
   7:         vin=7890
   8:     where
   9:        id=1

Not JPA Standard

Wonder why I haven’t shown you the annotation form of this non-version optimistic locking yet?  If you are currently using annotations to provide all of your object-database mappings, you will also be disappointed to learn JPA does not support optimistic locking outside of versioning (by number or timestamp).  So there are no JPA annotations to perform optimistic locking by field or dirty fields.  There is, however, a Hibernate annotations that can be used.  When mapping, add a parameter to the org.hibernate.annotations.Entity annotation to specify how to perform optimistic locking (as shown here).
   1: @Entity
   2: @org.hibernate.annotations.Entity(dynamicUpdate = true,
   3:         optimisticLock = OptimisticLockType.ALL)
   4: public class Vehicle {
   5:   // ...
   6: }
Of course, this annotation requires a Hibernate import and more tightly couples your domain class to Hibernate.

It’s Slower

Additionally, note that using all-column or dirty-column checks as part of the where-clause is a little slower.  When updating a single persistent object every so often, the speed may not be an issue.  But in systems dealing with large numbers of transactions, every millisecond counts.

Wrap Up

As you can see, Hibernate can perform some real time and code-saving work when it comes to optimistic locking.  The several options allow for you to pick a concurrent strategy in-line with your system architecture and business needs.  But under most circumstances, Hibernate optimistic locking without a version or timestamp will not work for highly concurrent, highly scalable applications, and doesn’t that pretty much describe most enterprise application needs today?  If you need more help on Hibernate, contact Intertech and consider taking our Complete Hibernate class.