Friday, September 5, 2014

Hibernate Locks/Locking Mechanism(JPA1/JPA2) :

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.get(classType, objectId, lockOptions)
  • 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]

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.

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

1 comment:

  1. Thanks for sharing this informative content , Great work
    Leanpitch provides online training in Product prototyping during this lockdown period everyone can use it wisely.
    icp-cat training

    ReplyDelete

Java 9 and Java11 and Java17, Java 21 Features

 Java 9 and Java11 and Java17 features along with explanation and examples in realtime scenarios Here's a detailed breakdown of Java 9, ...