Hibernate : Session Lock :-
Hibernate : Session Lock :-
The lock() method obtains the specified lock level upon the given object. It allows your application
to reattach the object to the session. It doesn't check or update the database as it assumes that the
database is in sync with the detached object.
Syntax: lock(Object entity,LockMode lockMode)
Specified by: lock in interface HibernateOperations
Parameters:
entity - the persistent instance to lock
lockMode - the lock mode to obtain
Throws:
DataAccessException - in case of Hibernate errors
There are five kind of locks that can be obtained -
LockMode.WRITE : It is obtained when Hibernate updates an object or saves new object.
LockMode.UPGRADE : Hibernate obtains this lock when using the SELECT <String> FOR UPDATE SQL command.
LockMode.UPGRADE_NOWAIT : Hibernate obtains this lock when using the SELECT <String> FOR UPDATE SQL command under the Oracle database server.
LockMode.READ : Hibernate obtains this lock either at the user's request or when neede for reading an object.
LockMode.NONE : Hibernate obtains this lock when a transaction finishes or during the start of a call to update() or saveOrUpdate().
Example : In this example we are updating record of student and using lock method to update record.
Here is main class code -
package net.roseindia.main;
import net.roseindia.table.Student;
import net.roseindia.util.HibernateUtil;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class HibernateUpdate {
public static void main(String args[]) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
int roll = 5;
Student student = (Student) session.get(Student.class, roll);
try {
session.lock(student, LockMode.UPGRADE); // Using lock()
student.setCourse("Hibernate");
//session.update(student);
//session.saveOrUpdate(student);
session.merge(student);
transaction.commit();
System.out.println("Update Successfully");
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}
Output :
Hibernate: select student0_.roll_no as roll1_0_0_, student0_.course as course0_0_, student0_.name as name0_0_ from student student0_ where student0_.roll_no=?
Hibernate: select roll_no from student where roll_no =? for updateHibernate: update student set course=?, name=? where roll_no=?
Update Successfully
I am trying to implement Optimistic locking in-order to avoid lost update situation. In my application when two user fetch same record and the first user updates it with some changes. This change is not visible to the second user who view the same record and he makes some changes by himself and updates it. Due to which the first persons change is lost. In-order to prevent this I have written the following but still the issue persist. I am new to this concept, not able to identify the issue.
I have tried to achieve this by reading doc 11.3.4. Customizing automatic versioning section.
-
The configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>server.bo.Dept</value>
<value>server.bo.Emp</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean id="deptDAO" class="server.dao.DeptDAOImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
</beans>
-
Entity Class
@Entity
@Table(name = "Dept")
@org.hibernate.annotations.Entity(dynamicUpdate = true,optimisticLock = OptimisticLockType.ALL)
public class Dept{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
Long id;
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy = "deptId")
@Fetch(FetchMode.SELECT)
@OrderBy(value = "id DESC")
List<Emp> Emplist;
public Dept() {}
// Getters and setters
}
-
DAO Impl
public class DeptDAOImpl extends HibernateDaoSupport implements DeptDAO {
@Transactional(readOnly = true, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public Dept getDeptById(Long id) {
Object param[] = new Object[]{id};
String query = "select d from Dept d where d.id=? and d.deleted='0'";
List<Dept> deptDetailsList = getHibernateTemplate().find(query,param);
Dept deptDetails = null;
if(deptDetailsList !=null && deptDetailsList .size()>0)
deptDetails = (Dept)deptDetailsList.get(0);
return deptDetails ;
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public long updateDept(Dept dept) {
if (dept.getId() == null) {
getSession().save(dept);
} else {
getSession().update(dept);
}
if (dept.getEmplist() != null) {
final int size = dept.getEmplist().size();
for (int i = size - 1; i >= 0; i--) {
Emp emp = dept.getEmplist().get(i);
if (emp.getDeptId() == null) {
emp.setDeptId(dept.getId());
}
if (RecordStatus.NEW.equals(emp.getRecordStatus())) {
getSession().save(emp);
} else if (RecordStatus.DELETED.equals(emp.getRecordStatus())) {
getSession().delete(emp);
} else if (RecordStatus.MODIFIED.equals(emp.getRecordStatus())) {
getSession().update(emp);
}
}
}
return dept.getId();
}
}
Hibernate offers pessimistic locking as an option for concurrency control. Hibernate’s pessimistic lock is actually a function of the underlying database. Hibernate does not actually ‘lock’ objects in memory. Locks are requested of the database by Hibernate operations like the following:
- session.load(classType, objectId, lockOptions)
- session.refresh(objectReference, lockOptions)
- session.buildLockRequest(lockOptions).lock(objectRef)
- this replaces the now deprecated session.lock(objectRef, lockMode) operations
- executing query with appropriate setLockOptions(lockOptions) called
- executing criteria with appropriate setLockOptions(lockOptions) called+
SQL RESULTING FROM UPDATE CALL
USING .LOCK() TO REATTACH
UPDATE CODE
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session sess = sf.openSession();
Transaction trx = sess.beginTransaction();
Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
trx.commit();
sess.close();
System.out.println("vehicle now detached: " + v);
//update the vehichle outside of session when detached.
v.setVin(123);
//reattach and update
sess = sf.openSession();
trx = sess.beginTransaction();
sess.update(v);
System.out.println("completed the update call");
trx.commit();
sess.close();
System.out.println("vehicle synchronized again: " + v);
LOCKING CODE
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session sess = sf.openSession();
Transaction trx = sess.beginTransaction();
Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
trx.commit();
sess.close();
System.out.println("vehicle now detached: " + v);
//update the vehichle outside of session when detached.
v.setVin(678);
//reattach using lock
sess = sf.openSession();
trx = sess.beginTransaction();
sess.buildLockRequest(LockOptions.NONE).lock(v);
System.out.println("completed the update call");
trx.commit();
sess.close();
System.out.println("vehicle synchronized again: " + v);
Hibernate:
select
vehicle0_.id as id0_0_,
vehicle0_.make as make0_0_,
vehicle0_.model as model0_0_,
vehicle0_.vin as vin0_0_
from
Vehicle vehicle0_
where
vehicle0_.id=?
vehicle now detached: Vehicle [id=1, make=Chevy, model=sedan, vin=345]
completed the update call
Hibernate:
update
Vehicle
set
make=?,
model=?,
vin=?
where
id=?
vehicle synchronized again: Vehicle [id=1, make=Chevy, model=sedan, vin=123]
SQL RESULTING FROM LOCK() CALL
Hibernate:
select
vehicle0_.id as id0_0_,
vehicle0_.make as make0_0_,
vehicle0_.model as model0_0_,
vehicle0_.vin as vin0_0_
from
Vehicle vehicle0_
where
vehicle0_.id=?
vehicle now detached: Vehicle [id=1, make=Chevy, model=sedan, vin=345]
completed the update call
vehicle synchronized again: Vehicle [id=1, make=Chevy, model=sedan, vin=678]
Follow us: @IntertechInc on Twitter | Intertech on Facebook
For more details on HIbernate pessimistic locking see the documentation here.
to reattach the object to the session. It doesn't check or update the database as it assumes that the
database is in sync with the detached object.
Syntax: lock(Object entity,LockMode lockMode)
Specified by: lock in interface HibernateOperations
Parameters:
entity - the persistent instance to lock
lockMode - the lock mode to obtain
Throws:
DataAccessException - in case of Hibernate errors
The configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>server.bo.Dept</value>
<value>server.bo.Emp</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean id="deptDAO" class="server.dao.DeptDAOImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
</beans>
Entity Class
@Entity
@Table(name = "Dept")
@org.hibernate.annotations.Entity(dynamicUpdate = true,optimisticLock = OptimisticLockType.ALL)
public class Dept{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
Long id;
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy = "deptId")
@Fetch(FetchMode.SELECT)
@OrderBy(value = "id DESC")
List<Emp> Emplist;
public Dept() {}
// Getters and setters
}
DAO Impl
public class DeptDAOImpl extends HibernateDaoSupport implements DeptDAO {
@Transactional(readOnly = true, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public Dept getDeptById(Long id) {
Object param[] = new Object[]{id};
String query = "select d from Dept d where d.id=? and d.deleted='0'";
List<Dept> deptDetailsList = getHibernateTemplate().find(query,param);
Dept deptDetails = null;
if(deptDetailsList !=null && deptDetailsList .size()>0)
deptDetails = (Dept)deptDetailsList.get(0);
return deptDetails ;
}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public long updateDept(Dept dept) {
if (dept.getId() == null) {
getSession().save(dept);
} else {
getSession().update(dept);
}
if (dept.getEmplist() != null) {
final int size = dept.getEmplist().size();
for (int i = size - 1; i >= 0; i--) {
Emp emp = dept.getEmplist().get(i);
if (emp.getDeptId() == null) {
emp.setDeptId(dept.getId());
}
if (RecordStatus.NEW.equals(emp.getRecordStatus())) {
getSession().save(emp);
} else if (RecordStatus.DELETED.equals(emp.getRecordStatus())) {
getSession().delete(emp);
} else if (RecordStatus.MODIFIED.equals(emp.getRecordStatus())) {
getSession().update(emp);
}
}
}
return dept.getId();
}
}
Hibernate offers pessimistic locking as an option for concurrency control. Hibernate’s pessimistic lock is actually a function of the underlying database. Hibernate does not actually ‘lock’ objects in memory. Locks are requested of the database by Hibernate operations like the following:
- session.load(classType, objectId, lockOptions)
- session.refresh(objectReference, lockOptions)
- session.buildLockRequest(lockOptions).lock(objectRef)
- this replaces the now deprecated session.lock(objectRef, lockMode) operations
- executing query with appropriate setLockOptions(lockOptions) called
- executing criteria with appropriate setLockOptions(lockOptions) called+
USING .LOCK() TO REATTACH
UPDATE CODE
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session sess = sf.openSession();
Transaction trx = sess.beginTransaction();
Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
trx.commit();
sess.close();
System.out.println("vehicle now detached: " + v);
//update the vehichle outside of session when detached.
v.setVin(123);
//reattach and update
sess = sf.openSession();
trx = sess.beginTransaction();
sess.update(v);
System.out.println("completed the update call");
trx.commit();
sess.close();
System.out.println("vehicle synchronized again: " + v);
LOCKING CODE
SessionFactory sf = new Configuration().configure().buildSessionFactory();
Session sess = sf.openSession();
Transaction trx = sess.beginTransaction();
Vehicle v = (Vehicle) sess.get(Vehicle.class, 1L);
trx.commit();
sess.close();
System.out.println("vehicle now detached: " + v);
//update the vehichle outside of session when detached.
v.setVin(678);
//reattach using lock
sess = sf.openSession();
trx = sess.beginTransaction();
sess.buildLockRequest(LockOptions.NONE).lock(v);
System.out.println("completed the update call");
trx.commit();
sess.close();
System.out.println("vehicle synchronized again: " + v);
Hibernate:
select
vehicle0_.id as id0_0_,
vehicle0_.make as make0_0_,
vehicle0_.model as model0_0_,
vehicle0_.vin as vin0_0_
from
Vehicle vehicle0_
where
vehicle0_.id=?
vehicle now detached: Vehicle [id=1, make=Chevy, model=sedan, vin=345]
completed the update call
Hibernate:
update
Vehicle
set
make=?,
model=?,
vin=?
where
id=?
vehicle synchronized again: Vehicle [id=1, make=Chevy, model=sedan, vin=123]
SQL RESULTING FROM LOCK() CALL
Hibernate:
select
vehicle0_.id as id0_0_,
vehicle0_.make as make0_0_,
vehicle0_.model as model0_0_,
vehicle0_.vin as vin0_0_
from
Vehicle vehicle0_
where
vehicle0_.id=?
vehicle now detached: Vehicle [id=1, make=Chevy, model=sedan, vin=345]
completed the update call
vehicle synchronized again: Vehicle [id=1, make=Chevy, model=sedan, vin=678]
Follow us: @IntertechInc on Twitter | Intertech on Facebook
For more details on HIbernate pessimistic locking see the documentation here.
The lock() method can be an important operation when looking at pessimistic operations, but it also has another less know use. The lock() method, with LockOptions.NONE, can be used to associate a detached object to a session and put the object back into a persistence context. Importantly, it does this without forcing an update of the database (as the update() or saveOrUpdate() method would). With LockOptions.NONE, it doesn’t get a database lock and it doesn’t even do a version check against the database. Importantly, changes that have been made to detached object before a call to the lock() method with LockOptions.NONE are not synchronized to the database. Therefore, only call lock() on detached objects that you know have not been modified outside of a persistent context.
As an example, look at these two code examples. On top is Hibernate code to reattach a detached object using a typical update method call. On the bottom is code to reattach a detached object using a .lock method call.
The lock() method can be an important operation when looking at pessimistic operations, but it also has another less know use. The lock() method, with LockOptions.NONE, can be used to associate a detached object to a session and put the object back into a persistence context. Importantly, it does this without forcing an update of the database (as the update() or saveOrUpdate() method would). With LockOptions.NONE, it doesn’t get a database lock and it doesn’t even do a version check against the database. Importantly, changes that have been made to detached object before a call to the lock() method with LockOptions.NONE are not synchronized to the database. Therefore, only call lock() on detached objects that you know have not been modified outside of a persistent context.
As an example, look at these two code examples. On top is Hibernate code to reattach a detached object using a typical update method call. On the bottom is code to reattach a detached object using a .lock method call.
Note: prior versions of Hibernate use sess.lock(v, LockMode.NONE); to perform the same operation as you see with buildLockRequest().lock() above. The .lock() methods have recently been deprecated.
Note: prior versions of Hibernate use sess.lock(v, LockMode.NONE); to perform the same operation as you see with buildLockRequest().lock() above. The .lock() methods have recently been deprecated.
Thanks in advance
Thanks in advance
Thanks for sharing this informative content , Great work
ReplyDeleteLeanpitch provides online training in Product prototyping during this lockdown period everyone can use it wisely.
icp-cat training