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
- As the name suggests the whole inheritance hierarchy is mapped to a single table.
- 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.
- Any fields that are not used in any branch of the hierarchy are set to NULL.
- By default JPA uses SINGLE_TABLE inheritance strategy.
Advantages
- It is simple and most suitable for small inheritance hierarchies.
- Only a single table is queried with the discriminator column value as a parameter to determine the type of the entity.
- Due to its simplicity it is easy
to manually inspect or modify the entities stored in the database.
Disadvantages
- The number of columns in the single table increase
undesirably with increase in number of classes in the hierarchy.
- The columns that are mapped to a subclass in the hierarchy
should be nullable.
- 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
- Each concrete class in the hierarchy is mapped to a separate table.
- 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.
- Each sibling in the inheritance hierarchy will have its own copy of the fields it inherits from the superclass.
- 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
- This strategy is most suitable for wide inheritance
hierarchies.
- Unlike SINGLE_TABLE inheritance strategy this strategy does
not require columns to be made nullable.
- Like SINGLE_TABLE inheritance strategy it is also easy to
inspect or modify manually.
Disadvantages
- The UNION of separate tables may impact performance.
- The duplication of columns that are mapped to superclass
fields causes the de-normalization of the database design.
- The presence of duplicate columns makes it hard to perform
aggregate (SQL) queries.
- 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
- Each class in the hierarchy is represented as a separate
table with no field duplication.
- 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.
- 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
- The JOINED strategy gives a nicely normalized database schema without any duplicate columns or unwanted nullable columns.
- This strategy is most suitable for large inheritance hierarchies, be the deep or wide.
Disadvantages
- This strategy makes the data harder to inspect or modify manually.
- 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.”