Professional Documents
Culture Documents
Object/relational mapping is the automated (and transparent) persistence of objects in a Java application to the
tables in a relational database, using metadata that describes the mapping between the objects and the database.
Hibernate simplifies:
Saving and retrieving your domain objects
Making database column and table name changes
Centralizing pre save and post retrieve logic
Complex joins for retrieving related items
Schema creation from object model
JPA:
JPA is a specification for Object Relational Mapping. It does not have any implementation and it specifies set of
guidelines for JPA implementations or vendors.
There are multiple JPA providers
1) Hibernate
2) Open JPA
3) Eclipse Link
Most popular among these is Hibernate. Actually Hibernate started as a ORM framework much before the JPA
inception. Starting from Release 3.2 Hibernate provided implementation for JPA. Hibernate provides extra features in
addition to JPA specification. We can think of Hibernate as a super set of JPA and JPA as sub set of Hibernate.
Hibernate features not yet supported by JPA
1) Wide identifier generator features.
2) More flush modes
3) Exclude fields from optimistic locking
4) Support for Java 8 Date and Time.
5) Versionless optimistic locking.
Page 1 of 37
Architecture:
The five core interfaces are used in just about every Hibernate application.
Session interface
1. The Hibernate notion of a session is something between connection and transaction.
2. It may be easier to think of a session as a cache or collection of loaded objects relating to a single unit of work.
Hibernate can detect changes to the objects in this unit of work.
3. We sometimes call the Session a persistence manager because it’s also the interface for persistence-related
operations such as storing and retrieving objects.
4. An instance of Session is lightweight and is inexpensive to create and destroy.
5. Hibernate sessions are not thread-safe and should by design be used by only one thread at a time.
Session-Factory interface
1. The application obtains Session instances from a Session-Factory. The Session-Factory is certainly not
lightweight! It’s intended to be shared among many application threads. There is typically a single Session-
Factory for the whole application—created during application initialization, for example. However, if your
application accesses multiple databases using Hibernate, you’ll need a Session-Factory for each database.
2. The Session-Factory caches generated SQL statements and other mapping metadata that Hibernate uses at
runtime. It also holds cached data that has been read in one unit of work and may be reused in a future unit of
work (only if class and collection mappings specify that this second-level cache is desirable).
Configuration interface
Page 2 of 37
2. The application uses a Configuration instance to specify the location of mapping documents and Hibernate-
specific properties and then create the Session-Factory.
Transaction interface
1. Hibernate applications may choose not to use this interface, instead managing transactions in their own
infrastructure code.
2. A Transaction abstracts application code from the underlying transaction implementation—which might be a
JDBC transaction, a JTA User-Transaction, or even a Common Object Request Broker Architecture (CORBA)
transaction— allowing the application to control transaction boundaries via a consistent API.
1. The Query interface allows you to perform queries against the database and control how the query is executed.
Queries are written in HQL or in the native SQL dialect of your database.
2. A Query instance is used to bind query parameters, limit the number of results returned by the query, and
finally to execute the query.
3. The Criteria interface is very similar; it allows you to create and execute object oriented criteria queries.
4. A Query instance is lightweight and can’t be used outside the Session that created it.
Criteria queries are ideal for dynamic queries. It makes the task of adding ordering, leaving some parts (e.g.
restrictions) out depending on some parameter.
HQL is ideal for static and complex queries coz it it’s much easier to read/understand HQL. It’s a bit more
powerful for join queries.
There is a difference in terms of performance between HQL and criteriaQuery, everytime you fire a query using
criteriaQuery, it creates a new alias for the table name which does not reflect in the last queried cache for any DB.
This leads to an overhead of compiling the generated SQL, taking more time to execute.
Basic configuration:
Managed environment
a. A J2EE application server such as JBoss, BEA WebLogic, or IBM WebSphere implements the
standard (J2EE-specific) managed environment
b. Pools resources such as database connections and allows transaction boundaries and security to be
specified declaratively (that is, in metadata).
c. In managed environments, Hibernate integrates with container-managed transactions and datasources.
Non-managed environment
a. A servlet container like Jetty or Tomcat provides a nonmanaged server environment for Java web
applications. A stand-alone desktop or command-line application is also considered non-managed.
Nonmanaged environments don’t provide automatic transaction or resource management or security
infrastructure. The application itself manages database connections and demarcates transaction
boundaries.
b. In the case of a non-managed environment, Hibernate handles transactions and JDBC connections.
Hibernate can be configured for deployment in both environments.
Non-Managed Environment
Hibernate
Session
Application
Page 4 of 37
hibernate.c3p0.idle_test_period=3000 The idle time in seconds before a connection is
automatically validated.
You declared the properties in a file named hibernate.properties, so you need only place this file in the application
classpath. It will be automatically detected and read when Hibernate is first initialized when you create a Configuration
object.
With Hibernate, hibernate acts as a client of the JDBC connection pool. The application code uses the Hibernate
Session and Query APIs for persistence operations and only has to manage database transactions, ideally using the
Hibernate Transaction API.
A managed environment handles certain cross-cutting concerns, such as application security (authorization and
authentication), connection pooling, and transaction management. J2EE application servers are typical managed
environments.
Although application servers are generally designed to support EJBs, you can still take advantage of the other managed
services provided, even if you don’t use EJB entity beans.
EJBs call the same Hibernate APIs as servlets, JSPs, or stand-alone applications: Session, Transaction, and Query. The
Hibernate-related code is fully portable between non-managed and managed environments.
Hibernate handles the different connection and transaction strategies transparently.
Hibernate
Application Server
EJB Transaction
Database Page 5 of 37
Resource
Manager
Query
Java already has a standard transaction API, JTA, which is used to control transactions in a
managed environment with J2EE. This is called container-managed transactions(CMT).
If a JTA transaction manager is present, JDBC connections are enlisted with this manager and
under its full control. This isn’t the case in a nonmanaged environment, where an application (or
the pool) manages the JDBC connections and JDBC transactions directly.
Managed and Non-managed environments can use different transaction methods. Since Hibernate needs to be
portable across these environments.The Hibernate Transaction interface abstracts the underlying JTA or JDBC
transaction (or, potentially, even a CORBA
transaction).
This underlying transaction strategy is set with the property hibernate. connection.factory_class, and it can take one of
the following two values:
a. net.sf.hibernate.transaction.JDBCTransactionFactory delegates to direct JDBC transactions. This
strategy should be used with a connection pool in a non-managed environment and is the default if no
strategy is specified.
b. net.sf.hibernate.transaction.JTATransactionFactory delegates to JTA.This is the correct strategy for
CMT, where connections are enlisted with JTA.
?xml version='1.0'encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="java:/hibernate/HibernateFactory">
<property name="show_sql">true</property>
<property name="connection.datasource">java:/comp/env/jdbc/AuctionDB</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property
name="transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup<
/property>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
Page 6 of 37
<property name="hibernate.ejb.interceptor"
value="com.comp.core.data.entities.AuditInterceptor"/>
<property name="hibernate.max_fetch_depth" value="3"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region_prefix" value="region1"/>
<property name="jboss.entity.manager.jndi.name" value="jndiname"/>
<property name="jboss.entity.manager.factory.jndi.name"
value="entityManagerFactory"/>
<mapping resource="auction/Item.hbm.xml"/>
<mapping resource="auction/Category.hbm.xml"/>
<mapping resource="auction/Bid.hbm.xml"/>
</session-factory>
</hibernate-configuration>
How did Hibernate know where the configuration file was located? When configure() was called, Hibernate searched
for a file named hibernate.cfg.xml in the classpath.
If you wish to use a different filename or have Hibernate look in a subdirectory, you must pass a path to the configure()
method:
If you have both hibernate.properties and hibernate.cfg.xml in the classpath, the settings of the XML configuration file
will override the settings used in the properties. This is useful if you keep some base settings in properties and override
them for each deployment with an XML configuration file.
You may have noticed that the SessionFactory was also given a name in the XML configuration file. Hibernate uses
this name to automatically bind the SessionFactory to JNDI after creation.
JNDI-bound SessionFactory
A JNDI bound Hibernate Session-Factory can simplify the lookup of the factory and the creation of new Session s.
Note that this is not related to a JNDI bound Datasource, both simply use the same registry!
If you wish to have the Session-Factory bound to a JNDI namespace, specify a name (eg. java:hibernate/Session-
Factory) using the property hibernate.session_factory_name. If this property is omitted, the Session-Factory will not be
bound to JNDI. (This is especially useful in environments with a read-only JNDI default implementation, e.g. Tomcat.)
When binding the Session-Factory to JNDI, Hibernate will use the values of hibernate.jndi.url, hibernate.jndi.class to
instantiate an initial context. If they are not specified, the default InitialContext will be used.
Page 7 of 37
Hibernate will automatically place the Session-Factory in JNDI after you call cfg.buildSessionFactory(). This means
you will at least have this call in some startup code (or utility class) in your application, unless you use JMX
deployment with the Hibernate Service (discussed later).
If you use a JNDI Session-Factory, an EJB or any other class may obtain the Session-Factory using a JNDI lookup.
We recommend that you bind the Session-Factory to JNDI in a managed environment and use a static singleton
otherwise. To shield your application code from these details, we also recommend hiding the actual lookup code for a
Session-Factory in a helper class, such as HibernateUtil.getSessionFactory ().
Persistence lifecycle:
Page 8 of 37
Transient objects:
In Hibernate, objects instantiated using the new operator aren’t immediately persistent. Their state is transient, which
means they aren’t associated with any database table row, and so their state is lost as soon as they’re de-referenced (no
longer referenced by any other object) by the application.
Hibernate considers all transient instances to be non-transactional; a modification to the state of a transient instance
isn’t made in the context of any transaction. This means Hibernate doesn’t provide any rollback functionality for
transient objects.
Objects that are referenced only by other transient instances are, by default, also transient. For an instance to transition
from transient to persistent state requires either a save () call to the persistence manager or the creation of a reference
from an already persistent instance.
Persistent objects:
Persistent instances might be objects instantiated by the application and then made persistent by calling the save ()
method of the persistence manager (the hibernate Session). Persistent instances are then associated with the persistence
manager.
A persistent instance might be an instance retrieved from the database by execution of a query, by an identifier lookup,
or by navigating the object graph starting from another persistent instance. In other words, persistent instances are
always associated with a Session and are transactional.
They might even be objects that became persistent when a reference was created from another persistent object already
associated with a persistence manager.
Page 9 of 37
Persistent instances participate in transactions—their state is synchronized (flushed) with the database at the end of the
transaction. When a transaction commits, state held in memory is propagated to the database by the execution of SQL
INSERT, UPDATE, and DELETE statements.
When the transaction ends, all the persistent object will not be updated to the database. Hibernate checks the objects
and finds which are modified then only it’ll update the database. This process is called dirty checking. Dirty objects are
which has had modified and not synchronized with database. This process gains performance with some databases and
loose performance with some databases. If you only want to update modified columns, you can enable dynamic SQL
generation by setting dynamic-update="true" in a class mapping.
Detached Objects:
In the case of Hibernate, however, these instances lose their association with the persistence manager when you close ()
the Session. We refer to these objects as detached, indicating that their state is no longer guaranteed to be synchronized
with database state; they’re no longer under the management of Hibernate.
Hibernate lets you reuse these instances in a new transaction by re-associating them with a new persistence manager.
(After re-association, they’re considered persistent.) This feature has a deep impact on how multi-tiered applications
may be designed.
Hibernate also provides an explicit detachment operation: the evict () method of the Session. This method will remove
the instance from the session cache. Changes to the instance will not be synchronized with the database. This operation
cascades to associated instances if the association is mapped with cascade="evict". However, this method is typically
used only for cache management (a performance consideration). It’s not normal to perform detachment explicitly.
Newly instantiated instances of a persistent class are considered transient by Hibernate. We can make a transient
instance persistent by associating it with a session:
save () method returns an identifier. If an INSERT has to be executed to get the identifier ( e.g. "identity" generator, not
"sequence"), this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is
problematic in a long-running conversation with an extended Session/persistence context.
Alternatively, you can assign the identifier using an overloaded version of save().
persist() makes a transient instance persistent. This method doesnot return the generated ID.However, it does not
guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen
at flush time. persist() also guarantees that it will not execute an INSERT statement if it is called outside of transaction
boundaries. This is useful in long-running conversations with an extended Session/persistence context.
DomesticCat pk = new DomesticCat();
pk.setColor(Color.TABBY);
pk.setSex('F');
pk.setName("PK");
Page 10 of 37
pk.setKittens( new HashSet() );
pk.addKitten(fritz);
sess.save( pk, new Long(1234) );
manag
persist ignored (but cascaded)
ed
remove
persist becomes managed
d
Operatio
State Result
n
manag
merge ignored (but cascaded)
ed
detach
merge becomes managed
ed
Page 11 of 37
Objects (state) associated with the persistence context is synchronized with the database at the end of the unit of work /
transaction. When a unit of work completes,state held in memory is propagated to the database by the execution of
SQL INSERT, UPDATE, and DELETE statements (DML). This procedure may also occur at other times. For example,
Hibernate may synchronize with the database before execution of a query. This ensures that queries are aware of
changes made earlier during the unit of work.
Hibernate doesn’t update the database row of every single persistent object in memory at the end of the unit of work.
Hibernate has a strategy for detecting which persistent object have been modified by the application. This is called
automatic dirty checking. An object with modifications that have not yet been propagated to the database is considered
dirty.
Hibernate is able to detect exactly which properties have been modified so that it’s possible to include only the columns
that need updating in the SQL UPDATE statement. This may bring some performance gains. By default, Hibernate
includes all columns of a mapped table in the SQL UPDATE statement (hence, Hibernate can generate this basic SQL
at startup, not at runtime). If you want to update only modified columns, you can enable dynamic SQL generation by
setting dynamic-update="true" in a class mapping.
The same mechanism is implemented for insertion of new records, and you can enable runtime generation of INSERT
statements with dynamic-insert="true". Hibernate excludes columns of mapped table which are null in SQL insert
statement. We recommend you consider this setting when you have an extraordinarily large number of columns in a
table (say, more than 50);
A persistence context is a cache of persistent entity instances. This means it remembers all persistent entity instances
you’ve handled in a particular unit of work. Automatic dirty checking is one of the benefits of this caching. Another
benefit is repeatable read for entities and the performance advantage of a unit of work-scoped cache.
For example, if Hibernate is told to load an object by primary key (a lookup by identifier), it can first check the
persistence context for the current unit of work. If the entity is found there, no database hit occurs—this is a repeatable
read for an application. The same is true if a query is executed through one of the Hibernate (or Java Persistence)
interfaces. Hibernate reads the result set of the query and marshals entity objects that are then returned to the
application. During this process, Hibernate interacts with the current persistence context. It tries to resolve every entity
instance in this cache (by identifier); only if the instance can’t be found in the current persistence context does
Hibernate read the rest of the data from the result set.
The persistence context cache offers significant performance benefits and improves the isolation guarantees in a unit of
work (you get repeatable read of entity instances for free). Because this cache only has the scope of a unit of work, it
has no real disadvantages, such as lock management for concurrent access—a unit of work is processed in a single
thread at a time.
The persistence context cache sometimes helps avoid unnecessary database traffic; but, more important, it ensures that:
The persistence layer isn’t vulnerable to stack overflows in the case of circular references in a graph of objects.
There can never be conflicting representations of the same database row at the end of a unit of work. In the
persistence context, at most a single object represents any database row. All changes made to that object may
be safely written to the database.
Likewise, changes made in a particular persistence context are always immediately visible to all other code
executed inside that persistence context and its unit of work (the repeatable read for entities guarantee).
You don’t have to do anything special to enable the persistence context cache. It’s always on and, for the
reasons shown, can’t be turned off.
Page 12 of 37
Metadata declaration:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="org.hibernate.auction.model.Category" table="CATEGORY">
<id name="id" column="CATEGORY_ID" type="long">
<generator class="native"/>
</id>
<property name="name" column="NAME" type="string"/>
</class>
</hibernate-mapping>
The access attribute allows you to specify how Hibernate should access property values of the POJO. The default
strategy, property, uses the property accessors (get/set method pair). The field strategy uses reflection to access the
instance variable directly. The following “property” mapping doesn’t require a get/set pair:
<property name="name" column="NAME" type="string" access="field"/>
For properties that map to columns, you can control whether they appear in the INSERT statement by using the insert
attribute and whether they appear in the UPDATE statement by using the update attribute.
The following property never has its state written to the database:
<property name="name" column="NAME" type="string" insert="false" update="false"/>
The property name of the Java Bean is therefore immutable and can be read from the database but not modified in any
way. If the complete class is immutable, set the immutable="false" in the class mapping.
In addition, the dynamic-insert attribute tells Hibernate whether to include unmodified property values in an SQL
INSERT, and the dynamic-update attribute tells Hibernate whether to include unmodified properties in the SQL
UPDATE:
<class name="org.hibernate.auction.model.User" dynamic-insert="true" dynamic-update="true">
...
</class>
These are both class-level settings. Enabling either of these settings will cause Hibernate to generate some SQL at
runtime, instead of using the SQL cached at startup time. The performance cost is usually small. Furthermore, leaving
out columns in an insert (and especially in an update) can occasionally improve performance if your tables define many
columns.
Auto generated Object Id:
Many legacy SQL data models use natural primary keys. A natural key is a key with business meaning: an attribute or
combination of attributes that is unique by virtue of its business semantics. Examples of natural keys might be a U.S.
Social Security Number or Australian Tax File Number. Distinguishing natural keys is simple: If a candidate key
attribute has meaning outside the database context, it’s a natural key.
Experience has shown that natural keys almost always cause problems in the long run. For these reasons, we strongly
recommend that new applications use synthetic identifiers (also called surrogate keys). Surrogate keys have no business
Page 13 of 37
meaning— they are unique values generated by the database or application.Hibernate has several built-in identifier
generation strategies.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Emp" table="EMPLOYEE">
<id name="id" type="long">
<column name="ID" />
<generator class="sequence-identity">
<param name="sequence">KTSEQ_USERGROUP</param>
</generator>
</id>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
increment generates identifiers of type long, short or int that are unique only when no other
process is inserting data into the same table. Do not use in a cluster. .
identity supports identity columns in DB2, MySQL, MS SQL Server, Sybase and
HypersonicSQL. The returned identifier is of type long, short or int.
sequence uses a sequence in DB2, PostgreSQL, Oracle, SAP DB, McKoi or a generator in
Interbase. The returned identifier is of type long, short or int
hilo uses a hi/lo algorithm to efficiently generate identifiers of type long, short or int,
given a table and column (by default hibernate_unique_key and next_hi
respectively) as a source of hi values. The hi/lo algorithm generates identifiers
that are unique only for a particular database.
seqhilo uses a hi/lo algorithm to efficiently generate identifiers of type long, short or int,
given a named database sequence.
uuid uses a 128-bit UUID algorithm to generate identifiers of type string, unique
within a network (the IP address is used). The UUID is encoded as a string of
hexadecimal digits of length 32.
guid uses a database-generated GUID string on MS SQL Server and MySQL.
native picks identity, sequence or hilo depending upon the capabilities of the underlying
database.
assigned lets the application to assign an identifier to the object before save() is called.
This is the default strategy if no <generator> element is specified.
select retrieves a primary key assigned by a database trigger by selecting the row by
some unique key and retrieving the primary key value
foreign uses the identifier of another associated object. Usually used in conjunction with
a <one-to-one> primary key association.
Page 14 of 37
The first thing you want to do with a Session is make a new transient object persistent.To do so, you use the save()
method:
Modifying the user after the session is closed will have no effect on its persistent representation in the database.
When the session is closed, user becomes a detached instance. It may be reassociated with a new Session by calling
update () or lock ().
user.setPassword("secret");
Session sessionTwo = sessions.openSession();
Transaction tx = sessionTwo.beginTransaction();
sessionTwo.update(user);
user.setUsername("jonny");
tx.commit();
sessionTwo.close();
It doesn’t matter if the object is modified before or after it’s passed to update(). The important thing is that the call to
update() is used to reassociate the detached instance to the new Session (and current transaction) and tells Hibernate to
treat the object as dirty (unless select-before-update is enabled for the persistent class mapping, in which case Hibernate
will determine if the object is dirty by executing a SELECT statement and comparing the object’s current state to the
current database state).
Lock:
Page 15 of 37
By specifying Lock-Mode.NONE here, we tell Hibernate not to perform a version check or obtain any database-level
locks when reassociating the object with the Session. If we specified LockMode.READ or LockMode.UPGRADE,
Hibernate would execute a SELECT statement in order to perform a version check (and to set an upgrade lock).
The SQL DELETE will be executed only when the Session is synchronized with the database at the end of the
transaction.After the Session is closed, the user object is considered an ordinary transient instance. The transient
Page 16 of 37
instance will be destroyed by the garbage collector if it’s no longer referenced by any other object. Both the in-
memory object instance and the persistent database row will have been removed.
The get() method is special because the identifier uniquely identifies a single instance of a class. Hence it’s common for
applications to use the identifier as a convenient handle to a persistent object. Retrieval by identifier can use the cache
when retrieving an object, avoiding a database hit if the object is already cached.
Hibernate also provides a load() method:
User user = (User) session.load(User.class, userID);
The load() method is older; get() was added to Hibernate’s API due to user request.
The difference is trivial:
1. If load() can’t find the object in the cache or database, an exception is thrown. The load() method never returns
null. The get() method returns null if the object can’t be found.
2. The load() method may return a proxy instead of a real persistent instance.A proxy is a placeholder that triggers
the loading of the real object when it’s accessed for the first time. On the other hand, get() never returns a
proxy.
Choosing between get() and load() is easy:
If you’re certain the persistent object exists, load() is a good option. If you aren’t certain there is a persistent
instance with the given identifier, use get() and test the return value to see if it’s null.
Using load() has a further implication:
The application may retrieve a valid reference (a proxy) to a persistent instance without hitting the database to
retrieve its persistent state. So load() might not throw an exception when it doesn’t find the persistent object in the
cache or database; the exception would be thrown later, when the proxy is accessed.
Page 17 of 37
5) You supply a Hibernate Interceptor and return Boolean.TRUE from Interceptor.isUnsaved() after checking the
instance in your code.
Detached instances have a non-null identifier value, so Hibernate treats them properly too.
if we had used the primitive type long in our persistent classes, we would have needed to use the following identifier
mapping in all our classes:
<id name="id" type="long" column="ID" unsaved-value="0">
<generator class="native"/>
</id>
The unsaved-value attribute tells Hibernate to treat instances of Category with an identifier value of 0 as newly
instantiated transient instances. The default value for the attribute unsaved-value is null;
The solution to this problem is using primitive wrapper class as our ID type (java.lang.Long in this case). In such case,
“null” will be treated as unsaved value.
Transitive Persistence:
Transitive persistence is a technique that allows you to propagate persistence to transient and detached sub-graphs
automatically.
Persistence by reachability is one of the models of Transitive persistence.
Persistence by reachability:
Persistence by reachability is a recursive algorithm. All objects reachable from a persistent instance become
persistent either when the original instance is made persistent or just before in-memory state is synchronized with the
data store.
In the purest form of persistence by reachability, the database has some top-level, or root, object from which all
persistent objects are reachable. Ideally, an instance should become transient and be deleted from the database if it isn’t
reachable via references from the root persistent object.
Neither Hibernate nor other ORM solutions implement this form.
Persistence by reachability is at best a halfway solution. It helps you make transient objects persistent and
propagate their state to the database without many calls to the persistence manager. But it isn’t a full solution to the
problem of making persistent objects transient and removing their state from the database. You can’t simply remove all
reachable instances when you remove an object; other persistent instances may hold references to them. It's difficult to
implement.
You can map entity associations in metadata with the following attributes:
1) cascade="none", the default, tells Hibernate to ignore the association.
Page 18 of 37
2) cascade="save-update" tells Hibernate to navigate the association when the transaction is committed and when
an object is passed to save() or update() and save newly instantiated transient instances and persist changes to
detached instances.
3) cascade="delete" tells Hibernate to navigate the association and delete persistent instances when an object is
passed to delete().
4) cascade="delete-orphan" Hibernate will delete any persistent entity instance that has been removed (de-
referenced) from the association (for example, from a collection).
5) cascade="all" means to cascade both save-update and delete, as well as calls to evict and lock.
6) cascade="all-delete-orphan" means the same as cascade="all" but, in addition, Hibernate deletes any persistent
entity instance that has been removed (dereferenced) from the association (for example, from a collection).
7)
Fetching strategies:
Fetching strategy defines how an associated object or a collection should be loaded, when the owning entity
object is loaded, and when you access an associated object or collection.
The problem of fetching object graphs efficiently (with minimal access to the database) has often been
addressed by providing association-level fetching strategies specified in metadata of the association mapping.
Hibernate allows you to choose among four fetching strategies for any association, in association metadata and
at runtime:
1) Immediate fetching—The associated object is fetched immediately, using a sequential database read (or cache
lookup).
2) Lazy fetching—The associated object or collection is fetched “lazily,” when it’s first accessed. This results in a
new request to the database (unless the associated object is cached).
3) Eager fetching—The associated object or collection is fetched together with the owning object, using an SQL
outer join, and no further database request is required.
4) Batch fetching—This approach may be used to improve the performance of lazy fetching by retrieving a batch
of objects or collections when a lazy association is accessed. (Batch fetching may also be used to improve the
performance of immediate fetching.)
Lazy fetching:
Hibernate defaults to a lazy fetching strategy for all entities and collections. This means that Hibernate by
default loads only the objects you’re querying for.
If you query for an Item object (let’s say you load it by its identifier), exactly this Item and nothing else is loaded into
memory:
Item item = (Item) session.load(Item.class, new Long(123));
This retrieval by identifier results in a single SQL statement that retrieves an Item instance. In the persistence context,
in memory, you now have this item object available in persistent state.
Understanding proxies:
Hibernate proxies are instances of runtime generated subclasses of your entity classes.
A proxy is initialized if you call any method other than identifier getter method (getId ()), a collection is initialized if
you start iterating through its elements or if you call any of the collection-management operations, such as size () and
contains ().
Page 19 of 37
The third line in this example triggers the execution of the SQL that retrieves an Item into memory. As long as you
access only the database identifier property, no initialization of the proxy is necessary. (Note that this isn’t true if you
map the identifier property with direct field access; Hibernate then doesn’t even know that the getId() method exists. If
you call it, the proxy has to be initialized.)
A proxy is useful if you need the Item only to create a reference, for example:
Item item = (Item) session.load(Item.class, new Long(123));
User user = (User) session.load(User.class, new Long(1234));
Bid newBid = new Bid("99.99");
newBid.setItem(item);
newBid.setBidder(user);
session.save(newBid);
You first load two objects, an Item and a User. Hibernate doesn’t hit the database to do this: It returns two proxies. This
is all you need, because you only require the Item and User to create a new Bid. The save(new bid) call executes an
INSERT statement to save the row in the BID table with the foreign key value of an Item and a User—this is all the
proxies can and have to provide. The previous code snippet doesn’t execute any SELECT!
If you call get () instead of load () you trigger a database hit and no proxy is returned. The get () operation always hits
the database (if the instance isn’t already in the persistence context and if no transparent second-level cache is active)
and returns null if the object can’t be found.
A JPA provider can implement lazy loading with proxies. The method names of the operations that are equivalent to
load() and get() on the EntityManager API are find() and getReference():
Item item = em.find(Item.class, new Long(123));
Item itemRef = em.getReference(Item.class, new Long(1234));
The first call, find (), has to hit the database to initialize an Item instance. No proxies are allowed—it’s the equivalent
of the Hibernate get () operation. The second call, getReference (), may return a proxy, but it doesn’t have to—which
translates to load() in Hibernate.
Hibernate provides an additional setting that is mostly useful for large collections; they can be mapped as extra lazy.
For example, consider the collection of bids of an Item:
The collection wrapper is now smarter than before. The collection is no longer initialized if you call size (), contains (),
or isEmpty ()—the database is queried to retrieve the necessary information. If it’s a Map or a List, the operations
containsKey() and get() also query the database directly.
The FetchType.EAGER provides the same guarantees as lazy="false" in Hibernate: the associated entity instance must
be fetched eagerly, not lazily.
Although all associations in Hibernate are completely lazy, but in JPA all @ManyToOne and @OneToOne
associations default to FetchType.EAGER!.
You can see that the SELECT queries only the ITEM table and retrieves a particular row. All entity associations and
collections aren’t retrieved. If you access any proxied association or uninitialized collection, a second SELECT is
executed to retrieve the data on demand.
Batch fetching:
If every entity association and collection is fetched only on demand, many additional SQL SELECT statements may be
necessary to complete a particular procedure.
For example, consider the following query that retrieves all Item objects and accesses the data of each items seller:
Page 21 of 37
List allItems = session.createQuery("from Item").list();
processSeller( (Item)allItems.get(0) ); //Get the seller object
processSeller( (Item)allItems.get(1) );
processSeller( (Item)allItems.get(2) );
Naturally, you use a loop here and iterate through the results, but the problem this code exposes is the same. You see
one SQL SELECT to retrieve all the Item objects, and an additional SELECT for every seller of an Item as soon as you
process it. All associated User objects are proxies. This is one of the worst-case scenarios we’ll describe later in more
detail: the n+1 selects problem. This is what the SQL looks like:
select items...
select u.* from USERS u where u.USER_ID = ?
select u.* from USERS u where u.USER_ID = ?
select u.* from USERS u where u.USER_ID = ?
The first optimization we now discuss is called batch fetching, and it works as follows: If one proxy of a User must be
initialized, batch-fetching will initialize several (based on batch-size) in the same SELECT.
If there are three Item instances in the persistence context, and that they all have a proxy applied to their seller
association, you may as well initialize all the proxies instead of just one.
<class name="User" table="USERS" batch-size="10">
...
</class>
You’re telling Hibernate to pre-fetch up to 10 uninitialized proxies in a single SQL SELECT, if one proxy must be
initialized. The resulting SQL for the earlier query and procedure may now look as follows:
select items...
select u.* from USERS u where u.USER_ID in (?, ?, ?)
The first statement that retrieves all Item objects is executed when you list () the query. The next statement, retrieving
three User objects, is triggered as soon as you initialize the first proxy returned by allItems.get (0).getSeller (). This
query loads three sellers at once—because this is how many items the initial query returned and how many proxies are
uninitialized in the current persistence context. You defined the batch size as “up to 10.” If more than 10 items are
returned, you see how the second query retrieves 10 sellers in one batch. If the application hits another proxy that
hasn’t been initialized, a batch of another 10 is retrieved— and so on, until no more uninitialized proxies are left in the
persistence context or the application stops accessing proxied objects.
If you now force the initialization of one bids collection, up to 10 more collections of the same type, if they’re
uninitialized in the current persistence context, are loaded right away:
select items...
Page 22 of 37
select b.* from BID b where b.ITEM_ID in (?, ?, ?)
In this case, you again have three Item objects in persistent state, and touching one of the unloaded bids collections.
Now all three Item objects have their bids loaded in a single SELECT.
Sub-select fetching:
A much better optimization is subselect fetching for this collection mapping:
<class name="Item" table="ITEM">
...
<set name="bids" inverse="true" fetch="subselect">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
Hibernate now initializes all bids collections for all loaded Item objects, as soon as you force the initialization of one
bids collection. It does that by rerunning the first initial query (slightly modified) in a
subselect:
select i.* from ITEM i
select b.* from BID b where b.ITEM_ID in (select i.ITEM_ID from ITEM i)
Obviously, the seller is no longer lazily loaded on demand, but immediately. Hence, a fetch="join" disables lazy
loading.
If you only enable eager fetching with lazy="false", you see an immediate second SELECT for the user object.
If you enable <many-to-one not-null="true"/>, Hibernate executes an inner join instead of an outer join.
You can also set the eager join fetching strategy on a collection:
<class name="Item" table="ITEM">
...
<set name="bids" inverse="true" fetch="join">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
Page 23 of 37
</set>
</class>
select i.*, b.* from ITEM i left outer join BID b on i.ITEM_ID = b.ITEM_ID
The resultset now contains many rows, with duplicate data for each Item that has many bids, and NULL fillers for all
Item objects that don’t have bids.
The number of tables joined in this case depends on the global hibernate. max_fetch_depth configuration property. By
default, no limit is set, so loading an Item also retrieves a Bid, a User, and an Address in a single select. Reasonable
settings are small, usually between 1 and 5. You may even disable join fetching for many-to-one and one-to-one
associations by setting the property to 0!
What you access is the bids collection of each Item. This collection isn’t initialized so far, the Bid objects for each item
have to be loaded with an additional query. This whole code snippet therefore produces n+1 selects.
2) With a subselect-based prefetch, you can reduce the number of selects to exactly two:
<set name="bids" inverse="true" fetch="subselect">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
3) We dont consider fetch="join" a common optimization for collection mappings as it will result in higher
memory consumption,
Page 24 of 37
every OUTER JOINed collection is a step toward a more serious Cartesian product problem.
This Cartesian product problem always appears if you try to fetch several “parallel” collections. The Item class has
more than one many-to-one association of bids an images with fetch="join".
<class name="Item">
...
<set name="bids" inverse="true" fetch="join">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
<set name="images" fetch="join">
<key column="ITEM_ID"/>
<composite-element class="Image">...
</set>
</class>
Result:
Hibernate executes an SQL SELECT that creates a product of the two collections:
select item.*, bid.*, image.*
from ITEM item
left outer join BID bid on item.ITEM_ID = bid.ITEM_ID
left outer join ITEM_IMAGE image on item.ITEM_ID = image.ITEM_ID
This resultset contains lots of redundant data.
Set fetch="join" on many-to-one and one-to-one association mappings. In rare cases, if you’re absolutely sure, enable
fetch="join" to disable lazy loading for particular collections.
Page 25 of 37
Hibernate associations:
If the association is navigable from one object to other it is uni-directional association. If the association is
navigable from both ends it is bi-directional association.
Many-to-one association:
public class Book {
private Long id;
private String isbn;
private String name;
private Publisher publisher;
private Date publishDate;
private Integer price;
private List chapters;
// Getters and Setters
}
To make use of this property, we can add a <many-to-one> mapping to the mapping definition of Book class. This will
add a column PUBLISHER_ID in the BOOK table and store the ID of associated publisher. Don’t forget to run the
schema update task for reflecting the changes to database.
<hibernate-mapping package="mo.org.cpttm.bookshop">
<class name="Book" table="BOOK">
<id name="id" type="long" column="ID">
<generator class="native"/>
</id>
<property name="isbn" type="string">
<column name="ISBN" length="50" not-null="true" unique="true" />
</property>
<property name="name" type="string">
<column name="BOOK_NAME" length="100" not-null="true" />
</property>
<property name="publishDate" type="date" column="PUBLISH_DATE" />
<property name="price" type="int" column="PRICE" />
<many-to-one name="publisher" class="Publisher" column="PUBLISHER_ID" />
</class>
</hibernate-mapping>
By default the lazy attribute of the association is true. so if we get book object, publisher will be loaded lazily means
proxy is retrieved along with book object.
Session session = factory.openSession();
try {
Book book = (Book) session.get(Book.class, id);
return book;
} finally {
session.close();
}
But when we access the publisher object through book.getPublisher() outside this method, lazy initialization exception
will occur.
Page 26 of 37
System.out.println(book.getName());
System.out.println(book.getPublisher().getName());
If we want the publisher object can be accessed outside the session, there will be two possible solutions.
One is to initialize the publisher explicitly, we can call the method Hibernate.initialize() for this task. This will force the
publisher object to be loaded from database.
Session session = factory.openSession();
try {
Book book = (Book) session.get(Book.class, id);
Hibernate.initialize(book.getPublisher());
return book;
} finally {
session.close();
}
Another solution is to turn off the lazy initialization feature for this association. This may decrease
the performance as the publisher object will be loaded together with the book object every time.
<hibernate-mapping package="mo.org.cpttm.bookshop">
<class name="Book" table="BOOK">
...
<many-to-one name="publisher" class="Publisher" column="PUBLISHER_ID"
lazy="false" />
</class>
</hibernate-mapping>
Making lazy= “false” we generate two select queries one for book and other for publisher. To optimize this we have to
include fetch strategies.
Fetch strategy:
To ask Hibernate to retrieve the information in one shot, i.e. issue a single SELECT statement with table join, we can
change the “fetch” attribute of the association to “join” (default is “select”).
<hibernate-mapping package="mo.org.cpttm.bookshop">
<class name="Book" table="BOOK">
...
<many-to-one name="publisher" class="Publisher" column="PUBLISHER_ID"
lazy="false" fetch="join" />
</class>
</hibernate-mapping>
If we inspect the SQL statements again, we will find that Hibernate is using a single SELECT statement with table join
to get the information. But is it also the case for using HQL queries?
Session session = factory.openSession();
try {
Query query = session.createQuery("from Book where isbn = ?");
query.setString(0, isbn);
Book book = (Book) query.uniqueResult();
return book;
} finally {
session.close();
Page 27 of 37
}
Unfortunately, two SELECT statements are still executing for this case. It is because any HQL query will be translated
into SQL statement directly. To apply the joining fetch strategy, we need to use the following HQL syntax.
Session session = factory.openSession();
try {
Query query = session.createQuery("from Book book left join fetch book.publisher where book.isbn
= ?");
query.setString(0, isbn);
Book book = (Book) query.uniqueResult();
return book;
} finally {
session.close();
}
Using left join fetching in HQL can also force the association to be initialized, if it is lazy. This is often used for
initializing lazy objects so that they can be accessed outside the session.
One-to-one Association:
The simplest way of mapping a one-to-one association is to treat it as a many-to-one association, but add a unique
constraint on it. You can declare the lazy, fetch and cascade attributes in the same way.
<hibernate-mapping package="mo.org.cpttm.bookshop">
<class name="Customer" table="CUSTOMER">
...
<many-to-one name="address" class="Address" column="ADDRESS_ID" unique="true" cascade="save-
update,delete" />
</class>
</hibernate-mapping>
We have mapped the unidirectional association from customer to address. If we want to make this
association bi-directional, we can map this association in the address side as a one-to-one
association, which references the “address” property of the Customer class.
public class Address {
private Long id;
private String city;
private String street;
private String doorplate;
private Customer customer;
// Getters and Setters
}
<hibernate-mapping>
<class name="Address" table="ADDRESS">
...
<one-to-one name="customer" class="Customer" property-ref="address" />
</class>
</hibernate-mapping>
Primary key association
The second way of mapping a one-to-one association is to let both objects have the same ID.Suppose we choose the
customer as the master object so that its ID is auto-generated. Then in the Address mapping definition, we declare the
ID as “foreign” type which references the customer property. Each address object will be assigned the same ID as its
customer. The “constrained” attribute means that the ID of Address has a foreign key constraint to the ID of Customer.
<hibernate-mapping package="mo.org.cpttm.bookshop">
<class name="Customer" table="CUSTOMER">
<id name="id" type="long" column="ID">
Page 30 of 37
<generator class="native"/>
</id>
...
<one-to-one name="address" class="Address" cascade="save-update,delete" />
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="Address" table="ADDRESS">
<id name="id" column="ID">
<generator class="foreign">
<param name="property">customer</param>
</generator>
</id>
...
<one-to-one name="customer" class="Customer" constrained="true" />
</class>
</hibernate-mapping>
For making a bi-directional association, you can declare a <one-to-one> mapping at both sides. If you want a
unidirectional association, you can omit the <one-to-one> mapping in the customer side but not the address side. That
means this association is only navigable from address to customer if it
is made unidirectional. If this is not what you want, you can reverse the declaration of <id> and <one-to-one>
mappings at both sides.
Named queries:
Hibernate allows queries to be defined in the mapping files.
<sql-query name= “ ”>
<![CDATA[
]]>
</sql-query>
Native queries:
Queries can also be expressed in native dialect of the database. This is useful if you want database specific
features.
session.creatSQLQuery(“query”)
Pagination:
Collections are pageable by using the Query interface with a filter:
Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();
Criteria Queries:
The interface org.hibernate.Criteria is used to query against a particular persistent class.
Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
Page 32 of 37
List cats = crit.list();
An individual query criterion is an instance of the interface org.hibernate.criterion.Criterion. The class
org.hibernate.criterion.Restrictions defines factory methods for obtaining certain built-in Criterion
types.
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
Projections:
Do not confuse the term "Projection" as it is used here with the Projection class. Projection in common terms means to
retrieve, and in SQL it means the "Select" clause. The "Select" clause is just a part of the services provided by the
Projection class. Following is SQL query for projection of all fields of the ORDER table in SQL:
Page 33 of 37
The above statement executes the corresponding SQL statement at the database server, populates the instances of the
Order ORM class, adds them to a list and returns the List object. Actually, the above statement is composed of two
statements:
List orders=criteria.list().
The combination of such dependent statements is known as method chaining. From now on I will be using this
technique extensively. The above code retrieves all the rows from the ORDER table. But what if only the data
contained in one of the fields has to be retrieved, as in the following SQL query:
Here, the Projection class comes into play. The above query can be rewritten into a Criteria query as:
List products=session.createCriteria(Product.class)
. setProjection(Projections.property(\"name\"))
.list();
above query returns list of property type values i.e list of strings.
It is clear from the above example that to query based on just one field, the fieldname is passed as an argument to the
property() method of the Projection class. The Projection instance returned in turn becomes an argument to the
setProjection() method. Similarly, to retrieve data based on two fields, ProjectionList has to be used. Hence the SQL
query:
Optimistic locking is a method used to prevent simultaneously access problem on the same entity for change, which
does not lock on the database level, in order to maintain the correct data.
For example, if two user wants to update same entity in different transactions, when first one saves and then second one
saves without getting updates from the first user’s change, who will be the winner?
Page 34 of 37
Most of the web applications, like ours, has such cases: Two users retrieve and modify a data on the page, then first
user saves the data a transaction and then second user modifies and saves the data in an another transaction. Here are 3
alternatives:
1. Last commit wins: Both updates are performed, the second user overwrites without seeing the first user changes and
without any error message
2. First commit wins: (Optimistic Locking) The update is performed, but second user gets error message, requiring
restart of the processes on the first users changes.
3. Merge conflicting update : The second user are prompted to merge changes.
Automatic Versioning
Hibernate provides automatic versioning for options 2 and 3, using a version field managed by hibernate.
<class name="MyClass">
<id ...>
<version name="version" column="VERSION" access="field">
...
</class>
<class name="MyClass">
<id ...>
<timestamp name="lastModifyDataTime" column="LAST_MODIFIY_DATE_TIME" access="field">
...
</class>
One more point, you should be aware of that hibernate ignores the versioning when getting object and updating fields
and then version are in the same session.
Hibernate3 provides support for queries via stored procedures and functions. Most of the following documentation is
equivalent for both. The stored procedure/function must return a resultset as the first out-parameter to be able to work
with Hibernate. An example of such a stored function in Oracle 9 and higher is as follows:
CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR
AS
st_cursor SYS_REFCURSOR;
BEGIN
OPEN st_cursor FOR
SELECT EMPLOYEE, EMPLOYER,
STARTDATE, ENDDATE,
REGIONCODE, EID, VALUE, CURRENCY
FROM EMPLOYMENT;
RETURN st_cursor;
END;
To use this query in Hibernate you need to map it via a named query.
You cannot use stored procedures with Hibernate unless you follow some procedure/function rules. If they do not
follow those rules they are not usable with Hibernate. If you still want to use these procedures you have to execute
Page 36 of 37
them via session.connection(). The rules are different for each database, since database vendors have different stored
procedure semantics/syntax.
A function must return a result set. The first parameter of a procedure must be an OUT that returns a result set. This is
done by using a SYS_REFCURSOR type in Oracle 9 or 10. In Oracle you need to define a REF CURSOR type. See
Oracle literature for further information.
Page 37 of 37