Tuesday, 29 October 2013

Optimistic and Pessimistic and lock modes in Hibernate

First we need to understand why do we need Optimistic and Pessimistic lock in hibernate.

The first thing to note about hibernate is that, hibernate never changes the default lock system (isolation level) provided by DBMS.  This is usually read committed or repeatable read.

Although we have a ways to override the default isolation in hibernate by specifying property hibernate.connection.isolation = 4 in hibernate configuration file. This will only be useful if we have hibernate managing the transaction for your application.

Here
1 - Read Uncommitted isolation
2 - Read Commited isolation
4 - Repeatable read isolation
8 - Serializable isolation

So lets say we have read committed as our isolation level.  Read committed allows shared read locks and exclusive write locks. Which means to say, multiple transaction can read data (shared read) the same record, but if we have a transaction that update record, it provide write locks and prevent other threads from reading the same records.

Consider this case in Hibernate. We have 2 threads A and B trying to modify the same record.

Figure :















Thread A and B both tries to read same record. Since there is no read lock to the DBMS for this isolation, both the threads are able to read the record.  Since this is a hibernate application, both the threads have their own persistent context and the records is been loaded to its persistent context.

Now assume both this thread modifies the record. Since hibernate has lazy loading feature, the modification remain in the persistent context and the is not flushed until the unit of work complete.
Now assuming the thread A completes the unit of work and all the changes are been flushed to the database.  The thread A acquire the write lock and the database records is updated. Tx for A ends and write lock is released. Now when Thread B tries to update the same records, since there is no write lock acquired to the record, it is able to acquire write lock himself and update the record. So the changes made by Thread A may be lost. Hence the need for lock in Hibernate.

The Above problem can be addressed by applying Optimistic Lock.

Enabling versioning in Hibernate (Optimistic Lock)

Each entity instance has a version column, which can be a number or a timestamp.  Hibernate increments an object’s version when it’s modified, compares versions automatically, and throws an exception if a conflict is detected. Consequently, you add this version property to all your persistent entity classes to enable optimistic locking.

Example :

Java Class

public class Employee {
...

// case when we want to use Number as version column
private int version ;

// case when we want to use timestamp as version column
private Date updatedDate;

}


HBM Mapping :
<class name = 'Employee' table='employee' >
...

<!-- In case the version is of type number -->
<version name='version' access='field' column='version'>
...
<!-- In case the version is of type timeStamp -->
<timestamp name='updatedDate' access='field' column='updated_date'>

</class>


Points to Note:
  • we have not added getter and setter method for version column. This is because we want this to be managed by the application.
  • The version property in application doesn't usually have any business purpose and is used by hibernate application for opt.
In theory, a timestamp is slightly less safe because 
  • Two concurrent transactions may both load and update the same employee in the same millisecond.
  • Retrieving the current time from the JVM isn’t necessarily safe in a clustered environment, where nodes may not be time synchronized. You can switch to retrieval of the current time from the database machine with the source="db" attribute on the <timestamp> mapping. but again, this would require another database select Query to retrieve the timestamp.

How Hibernate Manages versioning :

Every DML operation that has versioning enabled performs versioning checks. For Example, consider this - Employee instance was loaded into persistent context with version id 1. We did some modification to the entity and when the persistent context is flushed to database, hibernate detects that modification and increments the version of the entity to version 2. It then executes the SQL UPDATE to make this modification persistent in the database : 

Update employee set name='john', type='employee', version='2'
where id='1' and version='1' and name='john' and type='contract' .

If another concurrent unit of work updated and committed the same row, the version column no longer contains the value 1, and the row isn’t updated (check where clause).

Points to Note :
  • Hibernate takes care of increasing the version number by itself (after update).  This is not suppose to be managed by DBMS. We can have a trigger at DBMS which would take care of increasing the version number. but it will have some disadvantage :
    1. After each update, we may have to fire select query to reload the changed version id to persistent context.
  • Hibernate checks the row count for this statement as returned by the JDBC driver—which in this case is the number of rows updated, zero—and throws a StaleObjectStateException.
  • If you want to disable automatic increment for a particular value-typed property or collection, map it with the optimistic-lock="false" attribute.


But what happens if we are working on a legacy system where adding a column in table(versioning) is not possible. In that case, hibernate has an alternative strategy as below :

This alternative implementation of versioning checks the current database state against the unmodified values of persistent properties at the time the object was retrieved (or the last time the persistence context was flushed). You may enable this functionality by setting the optimistic-lock attribute on the class

<class name="Employee" table="employee" optimistic-lock="all">
....
</class>

The following SQL is fired when we flush the Employee instance :
update employee
set name='john', department='contract'
where id=1 and name='john' and type='contract'

so if any other transaction has update the employee row after the instance was loaded in persistent context, the where clause would fail. Hence we will get StaleObjectStateException.

Alternately we can set optimistic-lock="dirty" which will only include modified properties. This means two units of work may modify the same   object concurrently, and a conflict is detected only if they both modify the same value-typed property.


Pessimistic Locking in Hibernate :

The optimistic lock will work when we are dealing with entity instance. But consider the below case :

Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.setFlushMode(FlushMode.MANUAL);

Employee employee = (Employee) session.get(Employee.class, 1l) ;
String type = (String)session.createQuery(" select e.type from Employeee e where e.id = :id")
.setParameter("id", new Long("1"))
.uniqueResult();
session.flush();
tx.commit();
session.close();

In this example, we have set Flush Mode as Manual. This will not flush the changes to the employee object when we use hibernate Query language.

Now after the employee instance was loaded to the persistent context, lets say another thread modified the type of the employee with id =1 from "contract" to "employee". So when the hibernate query was fired, the result type was modified variable. In this case, we would have 2 different values for property 'type' on the same instance same persistent context.

This example is simplified, but it’s enough to illustrate how a unit of work that mixes entity and scalar reads is vulnerable to nonrepeatable reads, if the database transaction isolation level is read committed.

Instead of switching all database transactions into a higher and nonscalable isolation level,you obtain stronger isolation guarantees when necessary with the lock() method on the Hibernate Session:


Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();

Employee employee = (Employee) session.get(Employee.class, 1l) ;
session.lock(employee, LockMode.UPGRADE);

String type = (String)session.createQuery(" select e.type from Employeee e where e.id = :id")
.setParameter("id", new Long("1"))
.uniqueResult();
session.flush();
tx.commit();
session.close();


Using LockMode.UPGRADE results in a pessimistic lock held on the database for the employee instance. With this, no other transaction will be able to acquire lock to this employee row.
Shorten version :

Employee employee = (Employee) session.get(Employee.class, 1l,LockMode.UPGRADE) ;

Few points to Note  :

  • If some other transaction has already acquired the lock, LockMode.UPGRADE will wait till the lock is acquired. Hence Use LOCKMODE.UPDATE_NOWAIT that causes immediately failure it the lock cannot be acquired.
  • The duration of the lock held is for the single transaction .
  • If the value of the 'type' property is modified on same transaction and before the query is fired, We will not get the modified value .


Example :
session.setFlushMode(FlushMode.MANUAL);
Employee employee = (Employee) session.get(Employee.class, 1l) ;
System.out.println(employee.getType()); // Contract
session.lock(employee, LockMode.UPGRADE);
employee.setType("Employee") ; // Changed the value to Employee
String type = (String)session.createQuery(" select e.type from Employeee e where e.id = :id")
.setParameter("id", new Long("1"))
.uniqueResult();
System.out.println(type); // Contract
session.flush();
tx.commit();
session.close();

The reason is because the changed was not flushed before the query is fired. This is due to FlushMode.MANUAL. If the change was flushed before the query was executed or we had FlushMode.AUTO defined, we would get updated result.

Apart from LockMode.UPGRADE and LockMode.UPGRADE_NOWAIT, hibernate supports different lock modes:

Hibernate Lock Modes:

LockMode.NONE  : Don’t go to the database unless the object isn’t in any cache.
LockMode.READ  : Bypass all caches, and perform a version check to verify that the object in memory is the same version that currently exists in Database.
LockMode.UPDGRADE  : Bypass all caches, do a version check (if applicable), and obtain a database-level pessimistic upgrade lock.
LockMode.UPDGRADE_NOWAIT : The same as UPGRADE, but use a SELECT ... FOR UPDATE NOWAIT, if supported. This disables waiting for concurrent lock releases, thus throwing a locking exception immediately if the lock can’t be obtained.
LockMode.FORCE : Force an increment of the objects version in the database, to indicate that it has been modified by the current transaction.
LockMode.WRITE : Obtained automatically when Hibernate has written to a row in the current transaction.

Friday, 25 October 2013

Transaction isolation levels

First lets take a look at the different phenomena that governs the Isolation Level

Lost Update :
A lost update happens if two transactions try to update a row and then the second transaction rollback, causing both changes on the first to be lost. This happens if the systems doesn't implement locking.

Figure :
















Dirty Read :
A dirty read occurs if a one transaction reads changes made by another transaction that has not yet been committed. This is dangerous, because the changes made by the other transaction may later be rolled back,and invalid data may be written by the first transaction.

















Un-Repeatable Read
An unrepeatable read occurs if a transaction reads a row twice and reads different state each time. Another transaction may have written to the row and committed between the two reads

















A special case of unrepeatable read is the "second lost updates" problem. Imagine that two concurrent transactions both read a row: One writes to it and commits, and then the  second writes to it and commits. The changes made by the first writer are lost.


Phantom Read :
A phantom read is said to occur when a transaction executes a query twice, and the second result set includes rows that were’t visible in the first result set or rows that have been deleted. (It need not necessarily be exactly the same query.) This situation is caused by another transaction inserting or deleting rows between the execution of the two queries.


















Once we have defined the phenomenon, lets discuss the Transaction Isolation Level.

Following are the Isolation levels :

1. Read uncommitted :
 As the names suggest, it allow to dirty reads but not lost update in the system. One transaction may not write to a row if another uncommitted transaction (no to lost update) has already written to it. However, the transaction may be able to read data from the uncommited transaction (permits dirty reads).  This is archived in the database with exclusive write locks.

2. Read committed :
It allows unrepeatable read but not dirty read in the system. This may be achieved by using shared read locks and exclusive write locks. Reading transactions don’t block other transactions from accessing a row. However, an uncommitted writing transaction blocks all other transactions from accessing the row.

3.  Repeatable read :
This isolation mode permits neither unrepeatable reads nor dirty reads. however, Phantom reads may occur. Reading transactions block writing transactions (but not other reading transactions), and writing transactions block all other transactions .

4. Serializable :
This provides the strictest transaction isolation. This isolation level emulates serial transaction execution, as if transactions were executed one after another, serially, rather than concurrently.

Sunday, 6 October 2013

Mapping Class Inheritance in Hibernate

Hibernate has four different approach to represent an inheritance hierarchy.

  1. Table per concrete class with Implicit polymorphism : Use no explicit inheritance mapping and default runtime polymorphic behavior.
  2. Table per concrete class with unions : Discard polymorphism and inheritance relationship completely from the SQL schema
  3. Table per class hierarchy : Enable polymorphism by de-normalizing the SQL schema and utilizing a type discriminator column that holds that type information
  4. Table per subclass : Represent is a (inheritance) relationships as has a (foreign key) relationships. 


Hibernate Mapping Strategy :Table per subclass

Hibernate Mapping Strategy :Table per subclass 

As the name suggest, we have table define for each class(abstract, interface or concrete).

Example :



As in this Example, we have one superclass Employee and 2 subclass PermanentEmployee and ContractEmployee. At the database level, we have 3 tables Employee, PermanentEmployee and ContractEmployee. Here Primary key of Employee table acts as both primary key and foreign key for PermanentEmployee and ContractEmployee tables.

Java Class :

Employee.java
package com.demo.example1.pojo;

public class Employee {

private String name;
private String email;
private Long empId;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
}

PermanentEmployee.java
package com.demo.example1.pojo;

import java.util.Date;

public class PermanentEmployee extends Employee {
private String designation;
private Date joiningDate;
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}

public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}

}


ContractEmployee.java
package com.demo.example1.pojo;

import java.util.Date;

public class ContractEmployee extends Employee {
private Date contractDate;

public Date getContractDate() {
return contractDate;
}

public void setContractDate(Date contractDate) {
this.contractDate = contractDate;
}
}


hbm file : 
<hibernate-mapping package="com.demo.example1.pojo">
<class name="Employee" table="employee">
<id name="empId" column="empId" type="long">
<generator class="identity"/>
</id>
<property name="name" column="name" type="string"></property>
<property name="email" column="email"  type="string" ></property>
<joined-subclass name="PermanentEmployee" table="PermanentEmployee" >
<key column="perm_emp_id"/>
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</joined-subclass>
<joined-subclass name="ContractEmployee" table="ContractEmployee">
<key column="contract_emp_id"/>
<property name="contractDate" column="contractDate" type="timestamp" />
</joined-subclass>
</class>
</hibernate-mapping>

Main Class :

package com.demo.example1;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.demo.example1.pojo.ContractEmployee;
import com.demo.example1.pojo.Employee;
import com.demo.example1.pojo.PermanentEmployee;


public class Test {
public static void main(String[] args) {
// First unit of work
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
PermanentEmployee pm = new PermanentEmployee();
pm.setDesignation("perm_desg") ;
pm.setEmail("simon@test.com");
pm.setName("Simon") ;
session.save(pm);
ContractEmployee cm = new ContractEmployee();
cm.setEmail("nathen@test.com");
cm.setName("Nathen") ;
session.save(cm) ;
List<Employee> em = session.createQuery("from Employee").list();
System.out.println(em.size());
tx.commit();
session.close();
HibernateUtil.shutdown();
}
}

Output : 

Hibernate: 
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert 
        into
            employee
            (name, email) 
        values
            (?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert 
        into
            PermanentEmployee
            (designation, joiningDate, perm_emp_id) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert 
        into
            employee
            (name, email) 
        values
            (?, ?)
Hibernate: 
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert 
        into
            ContractEmployee
            (contractDate, contract_emp_id) 
        values
            (?, ?)
Hibernate: 
    /* 
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_1_.designation as designat2_2_,
        employee0_1_.joiningDate as joiningD3_2_,
        employee0_2_.contractDate as contract2_3_,
        case 
            when employee0_1_.perm_emp_id is not null then 1 
            when employee0_2_.contract_emp_id is not null then 2 
            when employee0_.empId is not null then 0 
        end as clazz_ 
    from
        employee employee0_ 
    left outer join
        PermanentEmployee employee0_1_ 
            on employee0_.empId=employee0_1_.perm_emp_id 
    left outer join
        ContractEmployee employee0_2_ 
            on employee0_.empId=employee0_2_.contract_emp_id
2


Advantage : 

  1. The SQL schema is Normalized.
  2. A polymorphic association to a particular subclass is represented as a foreign key referencing the table of that subclass 

Disadvantage : 

  1. Relies on outer join when querying for Employee class as shown in output .


Hibernate Mapping Strategy : Table per class Hierachy

Table per class Hierachy :  As the name suggest, the entire class hierarchy (abstract, interface and concrete class) is mapped to a single table. This table includes columns for all the properties of all classes in the hierarchy and the concrete subclass represented by a particular row is identified by the value of a type discriminator column.

Example :



As in this example, we have 3 different java classes and all the properties are mapped to a single table employee. Apart from this, we have another column "emp_type" which acts as a discriminator between PermanentEmployee and ContractEmployee class.

Java Files :

Employee Class
package com.demo.example1.pojo;

public class Employee {

private String name;
private String email;
private Long empId;

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}
}

PermanentEmployee  Class : 

package com.demo.example1.pojo;

import java.util.Date;

public class PermanentEmployee extends Employee {
private String designation;
private Date joiningDate;
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}

public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}

}

ContractEmployee  Class : 
package com.demo.example1.pojo;

import java.util.Date;

public class ContractEmployee extends Employee {
private Date contractDate;

public Date getContractDate() {
return contractDate;
}

public void setContractDate(Date contractDate) {
this.contractDate = contractDate;
}

}

hbm files:
<hibernate-mapping package="com.demo.example1.pojo">
<class name="Employee" table="employee">

<id name="empId" column="empId" type="long">
<generator class="identity"/>
</id>

<discriminator column="emp_type" />

<property name="name" column="name" type="string"></property>
<property name="email" column="email"  type="string" ></property>


<subclass discriminator-value="pe" name="PermanentEmployee">
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</subclass>

<subclass discriminator-value="ce" name="ContractEmployee">
<property name="contractDate" column="contractDate" type="timestamp" />
</subclass>

</class>
</hibernate-mapping>


Main Class : 
package com.demo.example1;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.demo.example1.pojo.ContractEmployee;
import com.demo.example1.pojo.Employee;
import com.demo.example1.pojo.PermanentEmployee;


public class Test {
public static void main(String[] args) {
// First unit of work

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

PermanentEmployee pm = new PermanentEmployee();
pm.setDesignation("lead") ;
pm.setEmail("peter@test.com");
pm.setName("Peter") ;

session.save(pm);

ContractEmployee cm = new ContractEmployee();
cm.setEmail("simon@test.com");
cm.setName("Simon") ;
session.save(cm) ;

List<Employee> em = session.createQuery("from Employee").list();
System.out.println(em.size());

tx.commit();
session.close();

HibernateUtil.shutdown();
}

}

Output :

Hibernate:
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert
        into
            employee_hie
            (name, email, designation, joiningDate, emp_type)
        values
            (?, ?, ?, ?, 'pe')
Hibernate:
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert
        into
            employee_hie
            (name, email, contractDate, emp_type)
        values
            (?, ?, ?, 'ce')
Hibernate:
    /*
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_.designation as designat5_1_,
        employee0_.joiningDate as joiningD6_1_,
        employee0_.contractDate as contract7_1_,
        employee0_.emp_type as emp2_1_
    from
        employee employee0_
2


Points to Note : 
  1. When defining properties in hbm file, make sure that discriminator is defined before we define any property element. 
  2. In case, if we dont have the freedom to add new discriminator column, we can apply a formula to calculate discriminator value for each row.
Example :
<discriminator formula="case when contractDate is not null then 'ce' else 'pe'  " />

Advantage: 
  1. This mapping is a winner in terms of both performance and simplicity. It's the best performing way to represent polymorphism.
  2. There is no complex join or subselects required which makes ad-hoc reporting possible.


Disadvantage :
  1. All properties declared by the subclass must be declared to be nullable. so loss of not null constraint may be serious problem from data integrity point of view.
  2. Voilates third normal form.


Saturday, 5 October 2013

Hibernate Mapping Strategy : Table Per Concrete Class with Unions

Table Per Concrete Class with Unions

Consider this Example :













As in this Example, we have an abstract class Employee which is inherited by 2 concrete class PermanentEmployee and ContractEmployee.  We have 2 tables PermanentEmployee and ContractEmployee to map this concrete class.

This mapping is very much similar to Table with Concrete class with implicit polymorphism hibernate mapping strategy except the fact that  in this strategy the database identifier is defined in abstract class which  is shared for by all concrete class in hierarchy.  Example Employee class has primary key "empId" which is shared by PermanentEmployee and ContractEmployee class.


Java Class :
Employee Class :
package com.demo.example1.pojo;

public class Employee {

private String name;
private String email;
private Long empId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Long getEmpId() {
return empId;
}
public void setEmpId(Long empId) {
this.empId = empId;
}

}

PermanentEmployee.java

package com.demo.example1.pojo;

import java.util.Date;

public class PermanentEmployee extends Employee {
private String designation;
private Date joiningDate;
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}

public Date getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(Date joiningDate) {
this.joiningDate = joiningDate;
}

}

package com.demo.example1.pojo;

import java.util.Date;

public class ContractEmployee extends Employee {
private Date contractDate;

public Date getContractDate() {
return contractDate;
}

public void setContractDate(Date contractDate) {
this.contractDate = contractDate;
}
}

hbm files looks like :

<hibernate-mapping package="com.demo.example1.pojo">

<class  name="Employee" abstract="true">

<id name="empId" column="empId" type="long">
<generator class="assigned"/>
</id>

<property name="name" column="name" access="field" />
<property name="email" column="email" access="field" />

<union-subclass table="permanentemployee" name="PermanentEmployee">
<property name="designation" column="designation" />
<property name="joiningDate" column="joiningDate" type="timestamp" />
</union-subclass>

<union-subclass table="contractemployee" name="ContractEmployee">
<property name="contractDate" column="contractDate" type="timestamp" />
</union-subclass>

</class>
</hibernate-mapping>



To Run :
package com.demo.example1;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.demo.example1.pojo.ContractEmployee;
import com.demo.example1.pojo.Employee;
import com.demo.example1.pojo.Message;
import com.demo.example1.pojo.PermanentEmployee;


public class Test {
public static void main(String[] args) {

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

PermanentEmployee pm = new PermanentEmployee();
pm.setDesignation("desg") ;
pm.setEmail("permEmployee@test.com");
pm.setName("Simon") ;
pm.setEmpId(1l);
session.save(pm);


ContractEmployee cm = new ContractEmployee();
cm.setEmail("contractEmployee@test.com");
cm.setName("Peter") ;
cm.setEmpId(2l);
session.save(cm) ;

List<Employee> em = session.createQuery("from Employee").list();
System.out.println(em.size());

tx.commit();
session.close();
HibernateUtil.shutdown();
}
}


OutPut :
Hibernate:
    /* insert com.demo.example1.pojo.PermanentEmployee
        */ insert
        into
            permanentemployee
            (name, email, designation, joiningDate, empId)
        values
            (?, ?, ?, ?, ?)
Hibernate:
    /* insert com.demo.example1.pojo.ContractEmployee
        */ insert
        into
            contractemployee
            (name, email, contractDate, empId)
        values
            (?, ?, ?, ?)
Hibernate:
    /*
from
    Employee */ select
        employee0_.empId as empId1_,
        employee0_.name as name1_,
        employee0_.email as email1_,
        employee0_.designation as designat1_2_,
        employee0_.joiningDate as joiningD2_2_,
        employee0_.contractDate as contract1_3_,
        employee0_.clazz_ as clazz_
    from
        ( select
            null as contractDate,
            joiningDate,
            empId,
            email,
            name,
            designation,
            1 as clazz_
        from
            permanentemployee
        union
        select
            contractDate,
            null as joiningDate,
            empId,
            email,
            name,
            null as designation,
            2 as clazz_
        from
            contractemployee
    ) employee0_
2


Points To Note :
  1. Employee class has been declared as abstract in hbm file. Otherwise a separate table for instance of the superclass is needed. Here in this example, "assigned" id generation strategy is used which allows us to manually set the id of the instance.
  2. We cannot use Native or identity or such id generate strategy when using this Hibernate Mapping Strategy. Reason is primary key is to be shared across all union subclass of hierarchy.


Friday, 4 October 2013

Hibernate Mapping Strategy : Table with Concrete class with implicit polymorphism.

Table with Concrete Class with Implicit Polymorphism :
As the name suggest, the polymorphic relationship is at java side while no such relationship exits on database layer.

Example :














As in the example,
We have a 3 seperate  java class - Employee, PermanentEmployee and ContractEmployee . Here Employee class is the super class of PermanentEmployee class and ContractEmployee class.

On the database side, we have just 2 tables. PermanentEmployee and ContractEmployee Table. As shown in the diagram, properties of Java Employee class is represented as columns in PermanentEmployee and ContractEmployee tables.

The mapping is also straightforward. since we have just 2 tables, we would have 2 hbm files, namely PermanentEmployee.hbm.xml and ContractEmployee.hbm.xml.

Points to Note: 
  1. Employee class in this example can be consider as an abstract class which shares some of the common properties between PermanentEmployee and ContractEmployee class. 
  2. Primary key is not shared by superclass. Each of the subclass has there own primary key.

Disadvantage of this approach:
  1. It doesn't support polymorphic relationship so well at database layer. Polymorphic relation are usually represented as foreign key relationship. If the subclass are mapped all mapped to different tables, a polymorphic association to their superclass cannot be represented as simple foreign key relationship.
  2. Since no polymorphic relationship exists for super class, a change in superclass would results in a change in all tables. Example, to add another property "department" in Employee class would results in change in PermanentEmployee and ContractEmployee Table and corresponding hbm files. 
  3. Polymorphic queries are also problematic.  Example, to query for all Employees with Email like '%some.com%', would be executed in multiple SQL SELECTS.
    • Select name, email from PermanentEmployee where  Email like '%some.com%' ;
    • Select name, email from ContractEmployeewhere  Email like '%some.com%' ;


When to Use :

  1. When implicit polymorphism is necessary when mapping legacy models where the tables do not share many common properties.
  2. This approach can also be used when modification to the superclass is highly unlikely in future.