Pages

Sunday, 6 January 2013

Hibernate as Persistence Provider and ORM Solution – Part III

Continues from Part II


Difference between Hibernate and JPA


JPA(Java Persistence API) is a specification that provides a POJO persistence model for object-relational mapping developed by the EJB 3.0 software expert group as part of JSR 220. Since it is not an implementation, we still have to choose an implementation. We can go for Hibernate, Toplink or any other ORM that implements JPA.
It is noticeable that although Hibernate implements JPA specification yet it has its own native ORM implementation as well.



JPA inheritance hierarchies

 

 SINGLE_TABLE – Single table per class hierarchy

  1. As the name suggests the whole inheritance hierarchy is mapped to a single table.
  2. Each object in the hierarchy is stored in exactly one row of that single table with the discriminator value stored in the discriminator column that specifies the type of the object.
  3. Any fields that are not used in any branch of the hierarchy are set to NULL.
  4. By default JPA uses SINGLE_TABLE inheritance strategy. 

Advantages

  1. It is simple and most suitable for small inheritance hierarchies.
  2. Only a single table is queried with the discriminator column value as a parameter to determine the type of the entity.
  3. Due to its simplicity it is easy to manually inspect or modify the entities stored in the database.


Disadvantages
  1. The number of columns in the single table increase undesirably with increase in number of classes in the hierarchy.
  2. The columns that are mapped to a subclass in the hierarchy should be nullable.
  3. Whenever a change is made to any of the class in the hierarchy, the mapped table also needs to be altered.

TABLE_PER_CLASS – Table per concrete class

  1. Each concrete class in the hierarchy is mapped to a separate table.
  2. The instance of each concrete class in the hierarchy is stored in exactly one row of its corresponding table which has columns for all the fields of the concrete class, including any inherited fields.
  3. Each sibling in the inheritance hierarchy will have its own copy of the fields it inherits from the superclass.
  4. A UNION of the separate tables mapped to each subclass is needed while querying on the superclass as siblings have their own copy of inherited fields.

Advantages
  1. This strategy is most suitable for wide inheritance hierarchies.
  2. Unlike SINGLE_TABLE inheritance strategy this strategy does not require columns to be made nullable.
  3. Like SINGLE_TABLE inheritance strategy it is also easy to inspect or modify manually.


Disadvantages
  1. The UNION of separate tables may impact performance.
  2. The duplication of columns that are mapped to superclass fields causes the de-normalization of the database design.
  3. The presence of duplicate columns makes it hard to perform aggregate (SQL) queries.
  4. It is not suitable for deep inheritance hierarchies in which the superclass fields are not ones we want to query on.

JOINED – Table per class

  1. Each class in the hierarchy is represented as a separate table with no field duplication.
  2. The instance of each class in the hierarchy is stored in multiple tables with one row in each of the tables that make up its class inheritance hierarchy.
  3. The is-a relation between a subclass and its superclass is represented as a foreign key relation from the “subtable” to the “supertable” and the mapped tables are JOINed to load all the fields of an entity.
Advantages
  1. The JOINED strategy gives a nicely normalized database schema without any duplicate columns or unwanted nullable columns.
  2. This strategy is most suitable for large inheritance hierarchies, be the deep or wide.
Disadvantages
  1. This strategy makes the data harder to inspect or modify manually.
  2. The JOIN operation needed to load entities may become a performance bottleneck.
Note: Hibernate does not properly handle discriminator columns whenever the JOINED strategy is used.

Using MappedSupperClass

Lets say we have some common fields in almost all our entity classes then in order to avoid the code duplication a nice way is to move those common fields to a MappedSupperClass. These classes are not mapped to any table in the underlying database. Entities that extend mapped super class define the table mappings. Mapped super classes are specified by decorating the class with the javax.persistence.MappedSuperclass annotation.

Entity classes and Serializable interface

The JPA specification mentions about the requirement of implementing Serializable interface for an entity class in the following words which is also applicable on Hibernate.
“..If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface”.

Therefore implementing Serializable interface is not required for an entity class unless its instance needs to be sent over the network to another tier as a detached entity or to be stored in the HTTP session etc.
It is worth mentioning here that the documentation of java.io.Serializable emphasizes the importance of explicitly adding serialVersionUID field in Serializable classes with some good reasons which is also given below.

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members.