In Hibernate, locking strategy can be either optimistic or pessimistic. Let’s first see the definition.
Optimistic Optimistic locking assumes that multiple transactions can complete without affecting each other, and that therefore transactions can proceed without locking the data resources that they affect. Before committing, each transaction verifies that no other transaction has modified its data. If the check reveals conflicting modifications, the committing transaction rolls back.
Pessimistic Pessimistic locking assumes that concurrent transactions will conflict with each other, and requires resources to be locked after they are read and only unlocked after the application has finished using the data. Hibernate provides mechanisms for implementing both types of locking in your applications. Let’s understand in detail :
Optimistic
When your application uses long transactions or conversations that span several database transactions, you can store versioning data so that if the same entity is updated by two conversations, the last to commit changes is informed of the conflict, and does not override the other conversation’s work. This approach guarantees some isolation, but scales well and works particularly well in read-often-write-sometimes situations.
Hibernate provides two different mechanisms for storing versioning information, a dedicated version number or a timestamp.
A version or timestamp property can never be null for a detached instance. Hibernate detects any instance with a null version or timestamp as transient, regardless of other unsaved-value strategies that you specify. Declaring a nullable version or timestamp property is an easy way to avoid problems with transitive reattachment in Hibernate, especially useful if you use assigned identifiers or composite keys.
Dedicated version number
The version number mechanism for optimistic locking is provided through a @Version annotation.
Example : The @Version annotation
@Entity
public class Flight implements Serializable {
...
@Version
@Column(name="OPTLOCK")
public Integer getVersion() { ... }
}
Here, the version property is mapped to the OPTLOCK column, and the entity manager uses it to detect conflicting updates, and prevent the loss of updates that would be overwritten by a last-commit-wins strategy.
The version column can be any kind of type, as long as you define and implement the appropriate UserVersionType.
Your application is forbidden from altering the version number set by Hibernate. To artificially increase the version number, see the documentation for properties LockModeType.OPTIMISTIC_FORCE_INCREMENT or LockModeType.PESSIMISTIC_FORCE_INCREMENT check in the Hibernate Entity Manager reference documentation.
Database-generated version numbers If the version number is generated by the database, such as a trigger, use the annotation @org.hibernate.annotations.Generated(GenerationTime.ALWAYS).
The name of the column holding the version number. Optional, defaults to the property name.
name
The name of a property of the persistent class.
type
The type of the version number. Optional, defaults to integer.
access
Hibernate’s strategy for accessing the property value. Optional, defaults to property.
unsaved-value
Indicates that an instance is newly instantiated and thus unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value, undefined, indicates that the identifier property value should be used. Optional.
generated
Indicates that the version property value is generated by the database. Optional, defaults to never.
insert
Whether or not to include the version column in SQL insert statements. Defaults to true, but you can set it to false if the database column is defined with a default value of 0.
Timestamp
Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications for other purposes as well. Timestamping is automatically used if you the @Version annotation on a Date or Calendar.
Example: Using timestamps for optimistic locking
@Entity
public class Flight implements Serializable {
...
@Version
public Date getLastUpdate() { ... }
}
Hibernate can retrieve the timestamp value from the database or the JVM, by reading the value you specify for the @org.hibernate.annotations.Source annotation. The value can be either org.hibernate.annotations.SourceType.DB or org.hibernate.annotations.SourceType.VM. The default behavior is to use the database, and is also used if you don’t specify the annotation at all.
The timestamp can also be generated by the database instead of Hibernate, if you use the @org.hibernate.annotations.Generated(GenerationTime.ALWAYS) annotation.
The name of the column which holds the timestamp. Optional, defaults to the property namel
name
The name of a JavaBeans style property of Java type Date or Timestamp of the persistent class.
access
The strategy Hibernate uses to access the property value. Optional, defaults to property.
unsaved-value
A version property which indicates than instance is newly instantiated, and unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value of undefined indicates that Hibernate uses the identifier property value.
source
Whether Hibernate retrieves the timestamp from the database or the current JVM. Database-based timestamps incur an overhead because Hibernate needs to query the database each time to determine the incremental next value. However, database-derived timestamps are safer to use in a clustered environment. Not all database dialects are known to support the retrieval of the database’s current timestamp. Others may also be unsafe for locking, because of lack of precision.
generated
Whether the timestamp property value is generated by the database. Optional, defaults to never.
Versionless optimistic locking
Although the default @Version property optimistic locking mechanism is sufficient in many situations, sometimes, you need rely on the actual database row column values to prevent lost updates.
Hibernate supports a form of optimistic locking that does not require a dedicated “version attribute”. This is also useful for use with modeling legacy schemas.
The idea is that you can get Hibernate to perform “version checks” using either all of the entity’s attributes, or just the attributes that have changed. This is achieved through the use of the @OptimisticLocking annotation which defines a single attribute of type org.hibernate.annotations.OptimisticLockType .
There are 4 available OptimisticLockTypes:
NONE optimistic locking is disabled even if there is a @Version annotation present
VERSION(the default) performs optimistic locking based on a @Version as described above
ALL performs optimistic locking based on all fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements
DIRTY performs optimistic locking based on dirty fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements
Example: OptimisticLockType.ALL mapping example
@Entity(name = "Person")
@OptimisticLocking(type = OptimisticLockType.ALL)
@DynamicUpdate
public static class Person {
@Id
private Long id;
@Column(name = "`name`")
private String name;
private String country;
private String city;
@Column(name = "created_on")
private Timestamp createdOn;
. . .
}
Pessimistic
Typically, you only need to specify an isolation level for the JDBC connections and let the database handle locking issues. If you do need to obtain exclusive pessimistic locks or re-obtain locks at the start of a new transaction, Hibernate gives you the tools you need.
Hibernate always uses the locking mechanism of the database, and never lock objects in memory.
The LockMode class
The LockMode class defines the different lock levels that Hibernate can acquire.
LockMode.WRITE
acquired automatically when Hibernate updates or inserts a row.
LockMode.UPGRADE
acquired upon explicit user request using SELECT ... FOR UPDATE on databases which support that syntax.
LockMode.UPGRADE_NOWAIT
acquired upon explicit user request using a SELECT ... FOR UPDATE NOWAIT in Oracle.
LockMode.READ
acquired automatically when Hibernate reads data under Repeatable Read or Serializable isolation level. It can be re-acquired by explicit user request.
LockMode.NONE
The absence of a lock. All objects switch to this lock mode at the end of a Transaction. Objects associated with the session via a call to update() or saveOrUpdate() also start out in this lock mode.
The explicit user request mentioned above occurs as a consequence of any of the following actions:
A call to Session.load(), specifying a LockMode.
A call to Session.lock().
A call to Query.setLockMode().
If you call Session.load() with option UPGRADE or UPGRADE_NOWAIT, and the requested object is not already loaded by the session, the object is loaded using SELECT ... FOR UPDATE. If you call load() for an object that is already loaded with a less restrictive lock than the one you request, Hibernate calls lock() for that object.
Session.lock() performs a version number check if the specified lock mode is READ, UPGRADE, or UPGRADE_NOWAIT. In the case of UPGRADE or UPGRADE_NOWAIT, SELECT ... FOR UPDATE syntax is used.
If the requested lock mode is not supported by the database, Hibernate uses an appropriate alternate mode instead of throwing an exception. This ensures that applications are portable.
I hope you have enjoyed this post and it helped you to understand the locking mechanism in hibernate using Java. Please like and share and feel free to comment if you have any suggestions or feedback.
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here:
Cookie Policy
Pradeep Mishra
Share post:
In Hibernate, locking strategy can be either optimistic or pessimistic. Let’s first see the definition.
Optimistic
Optimistic locking assumes that multiple transactions can complete without affecting each other, and that therefore transactions can proceed without locking the data resources that they affect. Before committing, each transaction verifies that no other transaction has modified its data. If the check reveals conflicting modifications, the committing transaction rolls back.
Pessimistic
Pessimistic locking assumes that concurrent transactions will conflict with each other, and requires resources to be locked after they are read and only unlocked after the application has finished using the data.
Hibernate provides mechanisms for implementing both types of locking in your applications. Let’s understand in detail :
Optimistic
When your application uses long transactions or conversations that span several database transactions, you can store versioning data so that if the same entity is updated by two conversations, the last to commit changes is informed of the conflict, and does not override the other conversation’s work. This approach guarantees some isolation, but scales well and works particularly well in read-often-write-sometimes situations.
Hibernate provides two different mechanisms for storing versioning information, a dedicated version number or a timestamp.
Dedicated version number
The version number mechanism for optimistic locking is provided through a
@Version
annotation.Example : The @Version annotation
Here, the version property is mapped to the
OPTLOCK
column, and the entity manager uses it to detect conflicting updates, and prevent the loss of updates that would be overwritten by a last-commit-wins strategy.The version column can be any kind of type, as long as you define and implement the appropriate
UserVersionType
.Your application is forbidden from altering the version number set by Hibernate. To artificially increase the version number, see the documentation for properties
LockModeType.OPTIMISTIC_FORCE_INCREMENT
orLockModeType.PESSIMISTIC_FORCE_INCREMENT
check in the Hibernate Entity Manager reference documentation.Example: Declaring a version property in
hbm.xml
integer
.property
.undefined
, indicates that the identifier property value should be used. Optional.never
.version
column in SQLinsert
statements. Defaults totrue
, but you can set it tofalse
if the database column is defined with a default value of0
.Timestamp
Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications for other purposes as well. Timestamping is automatically used if you the
@Version
annotation on a Date or Calendar.Example: Using timestamps for optimistic locking
Hibernate can retrieve the timestamp value from the database or the JVM, by reading the value you specify for the
@org.hibernate.annotations.Source
annotation. The value can be eitherorg.hibernate.annotations.SourceType.DB
ororg.hibernate.annotations.SourceType.VM
. The default behavior is to use the database, and is also used if you don’t specify the annotation at all.The timestamp can also be generated by the database instead of Hibernate, if you use the
@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)
annotation.Example 5.4. The timestamp element in
hbm.xml
property
.undefined
indicates that Hibernate uses the identifier property value.never
.Versionless optimistic locking
Although the default
@Version
property optimistic locking mechanism is sufficient in many situations, sometimes, you need rely on the actual database row column values to prevent lost updates.Hibernate supports a form of optimistic locking that does not require a dedicated “version attribute”. This is also useful for use with modeling legacy schemas.
The idea is that you can get Hibernate to perform “version checks” using either all of the entity’s attributes, or just the attributes that have changed. This is achieved through the use of the
@OptimisticLocking
annotation which defines a single attribute of typeorg.hibernate.annotations.OptimisticLockType
.There are 4 available OptimisticLockTypes:
NONE
optimistic locking is disabled even if there is a
@Version
annotation presentVERSION
(the default)performs optimistic locking based on a
@Version
as described aboveALL
performs optimistic locking based on all fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements
DIRTY
performs optimistic locking based on dirty fields as part of an expanded WHERE clause restriction for the UPDATE/DELETE SQL statements
Example:
OptimisticLockType.ALL
mapping examplePessimistic
Typically, you only need to specify an isolation level for the JDBC connections and let the database handle locking issues. If you do need to obtain exclusive pessimistic locks or re-obtain locks at the start of a new transaction, Hibernate gives you the tools you need.
The
LockMode
classThe
LockMode
class defines the different lock levels that Hibernate can acquire.SELECT ... FOR UPDATE
on databases which support that syntax.SELECT ... FOR UPDATE NOWAIT
in Oracle.update()
orsaveOrUpdate()
also start out in this lock mode.The explicit user request mentioned above occurs as a consequence of any of the following actions:
Session.load()
, specifying a LockMode.Session.lock()
.Query.setLockMode()
.If you call
Session.load()
with optionUPGRADE
orUPGRADE_NOWAIT
, and the requested object is not already loaded by the session, the object is loaded usingSELECT ... FOR UPDATE
. If you callload()
for an object that is already loaded with a less restrictive lock than the one you request, Hibernate callslock()
for that object.Session.lock()
performs a version number check if the specified lock mode isREAD
,UPGRADE
, orUPGRADE_NOWAIT
. In the case ofUPGRADE
orUPGRADE_NOWAIT
,SELECT ... FOR UPDATE
syntax is used.If the requested lock mode is not supported by the database, Hibernate uses an appropriate alternate mode instead of throwing an exception. This ensures that applications are portable.
I hope you have enjoyed this post and it helped you to understand the locking mechanism in hibernate using Java. Please like and share and feel free to comment if you have any suggestions or feedback.
Share this:
Like this: