You are on page 1of 35

Merge

In session, Hibernate guarantees no two Persistent objects represent the same row. Again, this
guarantee no
longer holds with Detatched objects. In fact, this problem can create very unwanted consequences.
Explore
the code below.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p1 = (BallPlayer)session.get(BallPlayer.class, 1L);
transaction.commit();
session.close();
//p1 is now detached.
session = sessionFactory.openSession();
transaction = session.beginTransaction();
BallPlayer p2 = (BallPlayer)session.get(BallPlayer.class, 1L);
//Oops! p2 represents the same persistent row as p1.
//When an attempt to reattach p1 occurs, an exception is thrown
session.update(p1);
transaction.commit();
session.close();

This code throws an exception when an attempt to reattach the Detached object at p1 is made.

Exception in thread "main" org.hibernate.NonUniqueObjectException: a


different object with the same identifier value was already associated
with the session: [com.intertech.domain.BallPlayer#1]
at
org.hibernate.engine.StatefulPersistenceContext.checkUniqueness
(StatefulPersistenceContext.java:613)
...

This is because Hibernate is trying to reinforce the guarantee that only a single instance of a Persistent
object
exist in memory.

The merge operation, helps to deal with this situation.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p1 = (BallPlayer)session.get(BallPlayer.class, 1L);
transaction.commit();
session.close();
//p1 is now detached.
session = sessionFactory.openSession();
transaction = session.beginTransaction();
BallPlayer p2 = (BallPlayer)session.get(BallPlayer.class, 1L);
BallPlayer p3 = (BallPlayer) session.merge(p1);

if (p2 == p3) {
System.out.println("They're equal");
}
transaction.commit();
session.close();

The merge() method is a little complex and works differently depending on what is in/out of the
persistence
context. Hibernate will first check whether a Persistent instance of that type already exists in the
persistent
context. It uses the object identifiers to check on this existence. If another instance exists, it copies the
state
of the Detached object (p1 above) into the existing Persistence object (p2 above). If no other instance
exists,
Hibernate just reattaches the Detached object.

In the example above, p2==p3 and one Persistent object exists. In the example below, two Persistent
objects
now exist and p2!=p3

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p1 = (BallPlayer)session.get(BallPlayer.class, 3L);
transaction.commit();
session.close();
//p1 is now detached.
session = sessionFactory.openSession();
transaction = session.beginTransaction();
BallPlayer p2 = (BallPlayer)session.get(BallPlayer.class, 1L);
BallPlayer p3 = (BallPlayer) session.merge(p1);
if (p2 == p3) {
System.out.println("They're equal");
}
System.out.println(p2);
System.out.println(p3);
transaction.commit();
session.close();

A complete diagram of the lifecycle now makes sense, given a description of the states and methods
that
transition the objects between states.

Object Relational Mapping (ORM)


An entire field of software engineering has grown from impedance mismatch.
ORM is the name given to automated technology developed to solve the mismatch problem. ORM
provides
transformations between object and relational models. Let the database do the things it does well
store and
retrieve large amounts of data. Let objects do the things they do well mimic the business domain.
ORM
technologies provide the tools to bridge the two in order to provide object state persistence in a
relational
database. This persistent automation should be transparent to developers.
ORM in Java means providing:

A Java API for performing data creates, read, update and delete operations on object state
(without directly using SQL or JDBC).

A Java API to query and instantiate objects based on query results.

A means for mapping metadata in objects to metadata of the database.

A mechanism for handling transactions across the object-relational environments.


A mechanism for handling concurrency and cache issues.

Persistent Framework
Whats a persistent framework?
- An ORM service that stores and retrieves objects into a relational database.
From the developers perspective, it should work transparently (or nearly transparently). Meaning the
object
developer should not have to know all the specifics about relational databases and SQL. A persistence
framework is a tool for simplifying the development and maintenance of object systems. Hibernate is
considered a persistent framework for Java!
So why do we need a persistence framework?
- To avoid hard coding SQL into our Java applications.
JDBC and SQL require Java programmers to be familiar with relational database details. Java JDBC work
is
tedious and diverts programmer attention from programming business logic. Programmers have to
constantly
concern themselves with binding query parameters, writing SQL, executing queries, scrolling the result
set and
retrieving the required data. Java programs are object-oriented (or at least should be) in nature
whereas
relational databases are tabular in nature. As shown above, this complicates the object-relational
mapping and
forces developers to think about problems in two different ways. Persistent frameworks help alleviate
the
ORM impedance mismatch. Therefore, a persistent framework makes coding faster and improves
maintenance. The persistent framework can also help to isolate the application from database specific
intricacies. Finally, a persistent framework can, in some cases, improve performance with appropriate
performance enhancements and caching.
Hibernate
Created by Gavin King.

Started in 2001.
Developed to meet needs he thought EJB container managed persistent (CMP) entity beans did not
achieve.

CMP did not scale.

Many, including King, believed CMP entity beans were too complex.

According to product documentation Hibernates goal is to relieve the developer from 95


percent of common data persistence related programming tasks.
Hibernate is an open source persistent framework. Hibernate team joined JBoss.org in 2003. Hibernate
also
supports the Enterprise Java Bean 3.0 persistence standardization effort. In fact, Hibernate is
considered an
implementation of the EJB 3.0 persistence standard. Hibernate implements EJB 3.0 with Hibernate
Annotations and EntityManager. Two members of the Hibernate development team are on the EJB
Expert
Group

Hibernate is available from hibernate.org. All Hibernate project documentation is also available on-line
at same
address. This class focuses on Hibernate 3.x (made available in 2005).
Java ORM/Persistent Frameworks
There are several persistent frameworks and ORM options in Java.

Enterprise JavaBeans Entity Beans

Java Data Objects

Castor

TopLink

Spring DAO

And many more


Some alternatives are open source products and some are commercial offerings. Many have been
around
longer than Hibernate.
Of course, there is always JDBC and SQL. Typically using the Data Access Object design pattern. DAO
offers a very simple method of mapping Java objects to databases. In general, Hibernate is considered
highly
portable, provides good mapping flexibility, and good performance.
Hibernate Example
The best way to learn most Java APIs and frameworks is to jump right in. In this chapter, you see your
first, albeit
simple, Hibernate application. You also see how to get Hibernate and install it into your application
environment.
In this section, you are also introduced to the Hibernate Architecture, API, configuration and mapping
files. The
Hibernate API that you use in most applications is very small and simple to use. Most of the real work
comes in
configuring Hibernate and mapping persistent objects to the database.
A Quick Hibernate Example
So how does Hibernate work? What does Hibernate look like? Perhaps the best place to start is with a
quick and
simple example.
Imagine you had an application with a Java type called BallPlayer.

public class BallPlayer {


private Long id;
private String name;
private String nickname;
private Calendar dob;
private String birthCity;
private short uniformNumber;
//getter and setter methods removed here for brevity.

BallPlayer objects are to be saved in a database table called Player.

create table player (


id integer primary key,
name varchar not null,
nickname varchar,
date_of_birth date,
city_of_birth varchar,
uniform_number integer
);

To create and persist a BallPlayer object into the Player table using the Hibernate API would look
similar to the
code below.

Calendar dob = Calendar.getInstance();


dob.set(1934, Calendar.FEBRUARY, 5);
BallPlayer player = new BallPlayer();

player.setName("Henry Louis Aaron");


player.setNickname("Hammerin' Hank");
player.setDob(dob);
player.setBirthCity("Mobile, AL");
player.setUniformNumber((short) 44);
SessionFactory sessionFactory = new
Configuration().configure(). buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(player);
transaction.commit();
session.close();

This code would launch the following SQL insert statement into the database.

INSERT INTO PLAYER VALUES(5,'Henry Louis Aaron','Hammerin''


Hank','1934-02-05','Mobile, AL',44)

Note: the SQL shown throughout class is an example of the SQL generated by Hibernate. The actual
SQL may
look different depending on the database.
Code to read, or maybe more appropriately recreate, a BallPlayer object from its persistent state
stored in the
database is similar.

SessionFactory sessionFactory = new


Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
BallPlayer aPlayer = (BallPlayer) session.get(BallPlayer.class, 1L);
transaction.commit();
session.close();

The SQL that Hibernate generates to fetch the objects state looks a little complex, but upon closer
scrutiny, it is
just a simple SQL select.

select ballplayer0_.id as id0_0_, ballplayer0_.name as name0_0_,


ballplayer0_.nickname as nickname0_0_, ballplayer0_.date_of_birth as
date4_0_0_, ballplayer0_.city_of_birth as city5_0_0_,
ballplayer0_.uniform_number as uniform6_0_0_ from Player ballplayer0_
where ballplayer0_.id=1

The magic which makes Hibernate work and be able to persist or recreate a BallPlayer to/from the
database comes
from a pair of XML files. First is a configuration file that tells Hibernate how to connect and talk to the
database.

<?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>
<property name="dialect"> org.hibernate.dialect.HSQLDialect</property>
<property name="connection.driver_class"> org.hsqldb.jdbcDriver</property>
<property name="connection.url"> jdbc:hsqldb:hsql:
//localhost/baseballdb</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="show_sql">true</property>
<mapping resource="com/intertech/domain/BallPlayer.hbm.xml" />
</session-factory>
</hibernate-configuration>

Hibernate uses JDBC under the covers. Therefore, just as in your JDBC code, Hibernate needs database
driver and
connection information.
Second is an XML mapping file shown below.

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.intertech.domain.BallPlayer" table="Player">
<id name="id">
<generator class="sequence">
<param name="sequence">common_seq</param>
</generator>
</id>
<property name="name" />
<property name="nickname" />
<property name="dob" column="date_of_birth" />
<property name="birthCity" column="city_of_birth" />
<property name="uniformNumber" column="uniform_number" />

</class>
</hibernate-mapping>

The mapping file tells Hibernate how persist properties of a BallPlayer into the columns of the Player
table (and
vice versa).
Much more on the Hibernate API, configuration, and mapping is forthcoming. However, with this simple
example
hopefully several facts become apparent. First, while Hibernate uses JDBC/SQL under the covers, it
removes the
developer from most (if not all) thought of the JDBC API and SQL. Second, the number of lines of Java
code to
persist or read an object like BallPlayer is small specially compared to JDBC code. Third, Hibernate
works to be
non-intrusive. It works to persist and recreate simple Java objects like BallPlayers. It does not require
those
objects classes to implement any specific interface or extend any special Hibernate class. This allows
developers to
create domain models without ties to the persistence architecture. In turn, this makes the domain
model more
flexible, maintainable and typically easier to test.

Hibernate Architecture and API


Hibernate is built on top of many Java APIs and other Java open source frameworks/APIs. The
architecture
is layered to keep you isolated from having to know the underlying APIs. In fact, while the available
Hibernate API is large, the API used by most application developers is relatively small. One only needs
to
know fewer than a dozen Hibernate classes to use Hibernate.

The Configuration object, as seen in the example code, is the first Hibernate object you use. It

represents a
configuration or properties file for Hibernate. The Configuration object is usually created once during
application initialization. The Configuration object reads and establishes the properties Hibernate uses
to get
connected to a database and configure itself for work. A Configuration object is used to create a
SessionFactory and then typically is discarded.
The SessionFactory is created from a Configuration object, and as its name implies it is a factory for
Session
objects.

The SessionFactory is an expensive object to create. It, like the Configuration object, is usually created
during
application start up. However, unlike the Configuration object, It should be created once and kept for
later
use.
The SessionFactory object is used by all the threads of an application. It is a thread safe object. One
SessionFactory object is created per database. Multiple SessionFactory objects (each requiring a
separate
Configuration) are created when connecting to multiple databases. The SessionFactory can also
provide
caching of persistent objects.

Session objects provide the main interface to accomplish work with the database. Persistent objects
are saved
and retrieved through a Session object. A Session object is lightweight and inexpensive to create. A
Session
object does the work of getting a physical connection to the database. Session objects maintain a
cache for a
single application thread (request).

Session objects are not thread safe. Therefore, session objects should not be kept open for a long time.
Applications create and destroy these as needed. Typically, they are created to complete a single unit
of
work, but may span many units.
When modifications are made to the database, Session objects are used to create a Transaction object.
A
Transaction represents a unit of work with the database (and potentially other systems). Transactions

in
Hibernate are handled by an underlying transaction manager and transaction (from JDBC, JTA or
CORBA).
Hibernate with use whatever transaction implementation is available (JDBC, JTA, CORBA, etc.). The
Hibernate Transaction object abstracts the developer from having to deal with the underlying
transaction
manager/transaction. This allows developers to use a Transaction Manager of their choice without
having to
code to a specific Transaction Manager. Transaction objects should be kept open for as short of time as
possible. There will be more information on Transactions and Transaction Management in a later
chapter in
class.
Query and Criteria objects are used to retrieve (and recreate) persistent objects. Query objects use
SQL or
Hibernate Query Language (HQL) string to retrieve data from the database and create objects. Criteria
uses an
object/method based means of constructing and executing a request to retrieve objects. Query and
Criteria will
also be covered in a later chapter in class.
Hibernate Installation/Setup
Hibernate can be downloaded in a single all-inclusive distribution file from www.hibernate.org.
Importantly,
from this distribution file, you will find the Hibernate JAR file (hibernate3.jar). This contains the core
Hibernate API. This JAR file must be on your applications classpath and made available to your IDE
when
creating the application.
However, Hibernate is built on top of many other open source packages. Therefore, several other JAR
files
are included in the distribution and many are required for Hibernate to work properly. The table below
lists
those that are required at the time of this release.

Additionally, you will need the database driver JAR that Hibernate uses to connect to your database.

Other JAR files are provided with the distribution and may be used for additional functionality. For
example
Hibernate ships with several caching engines and an open source connection pool facility. The
Hibernate
project has expanded to include several sub or ancillary projects and add-ons. These require
additional
Hibernate and open source JARs
The list above was created as of the release of Hibernate 3.3. The required JARs (and appropriate
version)
are changing with each release of Hibernate. Consult the latest Hibernate documentation/ReadMe files
for the
latest list of required JARs. Also, take care when upgrading any individual required JAR, even when you
are
aware of a more recent version.
The distribution file will also contain the Hibernate documentation.
Configuration
A Configuration object is created simply with a no-arguments constructor new Configuration(). When
created, classpath is searched for a file named hibernate.properties. The hibernate.properties file
provides
many configuration settings in key-value pair format. All hibernate.* properties are loaded into the
Configuration object when it is created.

hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:hsql://localhost/baseballdb
hibernate.connection.username=sa
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.show_sql=true

Optionally, the configure() method can be called on the Configuration object.

Configuration c = new Configuration();


c.configure();

When configure() is called, the classpath is searched for an XML configuration file called
hibernate.cfg.xml.
The hibernate.cfg.xml can also provide configuration parameters to Hibernate. Below the same
configuration
parameters are provided as in the hibernate.properties above, but in XML form in the
hibernate.cfg.xml.

<?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>
<property name="dialect"> org.hibernate.dialect.HSQLDialect</property>
<property name="connection.driver_class"> org.hsqldb.
jdbcDriver</property>
<property name="connection.url"> jdbc:hsqldb:hsql:
//localhost/baseballdb</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="show_sql">true</property>
<mapping resource="com/intertech/domain/BallPlayer.hbm.xml" />
</session-factory>
</hibernate-configuration>

When configuration parameters are duplicated, the parameters in the XML file will override those in
the
properties file. This actually provides some convenience. Many organizations have various levels of
systems
(dev, test, stage, production, etc.). Overriding allows level-independent information to be set in one file
while
level-dependent info is set in another file.

You can use a different configuration file name and location for the XML configuration file. The
configure
method is overloaded. Provide a String to specify the name and location of the XML configuration file
if
hibernate.cfg.xml is not used.

c.configure(/com/intertech/domain/myconfig.cfg.xml);

If this does not provide you enough options to configure Hibernate, well then you have two other
options.
You can set configuration properties programmatically with setProperty().

c.setProperty(org.hibernate.cfg.Environment.SHOW_SQL, "true");

Using setProperty overrides what is in hibernate.properties and hibernate.cfg.xml. When starting the
application, you can also set configuration properties from the command line.

java -Dhibernate.show_sql=true Myapplication

Given the number of configuration parameters that must usually be set, this last option is usually not
appropriate for general configuration. Command line parameters will override what is in
hibernate.properties,
but be overridden by what is in hibernate.cfg.xml. Use a dynamic place holder in the hibernate.cfg.xml
file if
you wish to pass a parameter from the command line.

<property name="show_sql">${displaysql}</property>

The command line call must use the same placeholder name.

java displaysql=true Myapplication

The goal of building a Configuration object is to eventually create a SessionFactory with a call to
buildSessionFactory(). Recall, the Configuration object is used just to establish the SessionFactory
object.
Then it is forgotten and disposed of (lost to garbage collection). For this reason many Hibernate
developers
will use method chaining to create the Configuration object and SessionFactory. The Configuration
object and
many Hibernate objects support method chaining, so the typical call to create a SessionFactory is
shown
below.

SessionFactory sessionFactory = new Configuration().configure().


setProperty(Environment.SHOW_SQL,"true").buildSessionFactory();

Configuration Properties
So what information can be specified in the hibernate.properties or hibernate.cfg.xml file? The Javadoc
for org.
hibernate.cfg.Environment list and document all the possible configuration properties. A complete
review of
all properties is not possible or warranted here, but a review of some of the more commonly used
properties
is provided.
Possibly the most important configuration property is the dialect parameter.

hibernate.dialect=org.hibernate.dialect.HSQLDialect

The dialect specifies to Hibernate the particular brand and possibly version of a database you are
using.

A list of the out-of-the-box dialects currently supported by Hibernate is listed in the table below.

Specifying a dialect allows Hibernate to use defaults for many of the other configuration properties.
The JDBC connection properties have already been seen.

hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:hsql://localhost/baseballdb
hibernate.connection.username=sa
hibernate.connection.password=sa

Most applications will want to use a connection pool when working with the database. Hibernate comes
with
its own connection pooling algorithm and can be configured.

hibernate.connection.pool_size=100

This connection pooling system is very limited and the Hibernate documentation even warns about its
use in
production systems.

It is intended to help you get started and is not intended for use in
a production system or even for performance testing.

More appropriately, Hibernate recommends you use one of the many third-party connection pools.
Hibernate was built to work with many, and ships with one open source third-party connection pool
called
C3PO. In addition to making the C3PO library available on the class path, many configuration
parameters
provide the pool settings.

hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=25
hibernate.c3p0.timeout=4000
hibernate.c3p0.max_statements=100
hibernate.c3pO.idle_test_period=3600

Most Java Enterprise applications run in an application server. The application server provides a
datasource
which in turn provides a connection pool. In Hibernate terminology, applications that run in an
application
server operate in a managed environment. In a managed environment, things like transactions,
security and
connection pools are used by Hibernate but provided outside of it. Applications that do not run in a
managed
environment operate it what Hibernate calls a non-managed environment. In non-managed
environments, the
application and/or Hibernate must manage their own transactions, security, connection pool, etc. More

information on managed and non-managed environments will be covered later in class.


In a managed environment, a different set of configuration properties are used to provide Hibernate
information about the datasource. The dialect property must still be provided, but in lieu of the
connection
information, a single JNDI lookup name for the datasource is provided.

hibernate.connection.datasource=java:/comp/env/jdbc/baseball

Additional properties can be provided to specify things such as the URL for the JNDI provider and class
of
the JNDI InitialContextFactory.
In a managed environment, after the SessionFactory is created, you may want to bind it into naming
service
with a JNDI name. Specify hibernate.session_factory_name in the properties to have Hibernate bind
your
SessionFactory object to the name after it is created.

hibernate.session_factory_name=java:/hibernate/MySessionFactory

A few other important debugging properties allow you, as a developer, to see the SQL executed by
Hibernate.
The show_sql property has Hibernate write all the SQL executed in the JVM console.

hibernate.show_sql=true

To display the same SQL to the console but in a more pretty format, turn on SQL formatting.

hibernate.format_sql=true

An example of the normal SQL displayed and the formatted SQL is shown below.
REGULAR SHOW_SQL
Hibernate: select ballplayer0_.id as id0_0_, ballplayer0_.name as
name0_0_, ballplayer0_.nickname as nickname0_0_,
ballplayer0_.date_of_birth as date4_0_0_, ballplayer0_.city_of_birth
as city5_0_0_, ballplayer0_.uniform_number as uniform6_0_0_ from
Player ballplayer0_ where ballplayer0_.id=?
FORMATTED
Hibernate:
select
ballplayer0_.id as id0_0_,
ballplayer0_.name as name0_0_,
ballplayer0_.nickname as nickname0_0_,

ballplayer0_.date_of_birth as date4_0_0_,
ballplayer0_.city_of_birth as city5_0_0_,
ballplayer0_.uniform_number as uniform6_0_0_
from
Player ballplayer0_
where
ballplayer0_.id=?

Lastly, applications cause several SQL statements to get launched and it can be difficult to determine
what
SQL is used for which operation. Use the use_sql_comments property to have Hibernate generate and
display comments with the SQL output to the console.

Hibernate:
/* load com.intertech.domain.BallPlayer */ select
ballplayer0_.id as id0_0_,
ballplayer0_.name as name0_0_,
ballplayer0_.nickname as nickname0_0_,
ballplayer0_.date_of_birth as date4_0_0_,
ballplayer0_.city_of_birth as city5_0_0_,
ballplayer0_.uniform_number as uniform6_0_0_
from
Player ballplayer0_
where
ballplayer0_.id=?

Mapping Files
The hibernate.cfg.xml can also provide the location of mapping documents. In the example above, the
BallPlayer.hbm.xml mapping document is specified as a mapping resource in addition to all the config
properties.

<mapping resource="com/intertech/domain/BallPlayer.hbm.xml" />

The hibernate.properties file cannot specify mapping resources.

If not specified in the hibernate.cfg.xml, the mappings files can also be specified programmatically on
the
Configuration object.

Configuration c = new Configuration().configure();


c.addResource(com/intertech/domain/BallPlayer.hbm.xml);

Mapping files specify how class properties and associations to other objects are mapped to the
database
table/columns. Details on the organization and content of the mapping files will be covered throughout

class,
but will start in the next chapter. Traditionally, there is one mapping file per class. The name of the
mapping
file conventionally takes the form Classname.hbm.xml. For example, the BallPlayer class has a
BallPlayer.
hbm.xml mapping file. The mapping file is also conventionally stored in the same package with the
domain
class it maps to the database.

Following the conventions regarding name and location of the mapping file are not required, but when
they
are, a convenience follows. Namely, using these conventions allows the addClass() method to be used
to load
the mappings versus addResource().

c.addClass(com.intertech.domain.BallPlayer.class);

The mapping file must follow the Hibernate document type definition (DTD) (currently version 3.0).
Persistant Classes and POJO
Hibernate manages the persistence of Java objects to database tables/columns. But what are the rules
around
the types of Java objects and properties that is can persist? What must the Java objects look like?
How
does Hibernate know what to map to the database.
In this chapter, you explore Hibernate persistent classes and the mapping file that defines how they
are
stored in a database.
The mapping file can be quite complex. While no means an exhaustive look at class and property
mapping,
some of the more common class and property settings are covered in this chapter. More details about
persistent objects and their association to other objects will be covered in subsequent chapters.
Persistent Classes
Hibernate is designed to persist Java objects to a relational database.

Allowing you to develop, work with and focus on objects that represent domain or business
entities.

Allowing you to ignore details of SQL and relational databases while programming your
system.
Java classes whose objects or instances will be stored in database tables are called persistent
classes in
Hibernate. Another way to say this is that persistent classes are those that are mapped to database
tables.
Hibernate works best at persisting plain ordinary Java objects (POJOs). Also known as plain old Java
objects. JavaBeans, as a subset of POJOs, work equally well. Hibernate can persist other types of
entities

apart from POJOs and JavaBean objects (more on these later).


POJOs
POJOs are simple object state holders. A class with properties (member variables) accessible by public
getter
and setter methods (providing good data encapsulation). Actually, even the getters and setters are
optional as
far as Hibernate is concerned (more in a bit). Hibernate can actually access member variables directly,
if
needed.

public class
private
private
private
private
private
private

BallPlayer {
Long id;
String name;
String nickname;
Calendar dob;
String birthCity;
short uniformNumber;

public BallPlayer(String name, String nickname, Calendar dob, String


birthCity, short uniformNumber) {
this.name = name;
this.nickname = nickname;
this.dob = dob;
this.birthCity = birthCity;
this.uniformNumber = uniformNumber;
}
public BallPlayer(){
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Calendar getDob() {
return dob;
Persistent Object Updates and Automatic Dirty Checking
While a session remains open, if a Persistent object is modified, its data is kept synchronized with the

database. The
data will be synchronized (but not committed) when session.flush() is called. It will be synchronized
and committed
when the transaction is committed. It may be synchronized at other points. For example, before
Hibernate
performs some queries of the database.
For example, in the code below a change to a BallPlayer object during a session does not require any
special method
call to persist the change.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
p.setNickname("Bambino");
transaction.commit(); //new nickname is synched and committed here
session.close();

Hibernate knows and tracks the Persistent object and its state change. Merely committing the
transaction will cause
the new data to be synchronized to the database with an update statement.

Update Player set name=?, nickname=?, date_of_birth=?,


city_of_birth=?, uniform_number=? Where id=?

Hibernate monitors all Persistent objects (i.e. the persistent context). At the end of a unit of work, it
knows which
objects have been modified. It then calls update statements on all updated objects. This process of
monitoring and
updating only objects that have changed is called automatic dirty checking. As opposed to updating all
Persistent
objects at the end of each work, automatic dirty checking can offer significant performance savings.

Detached State
Once a session is closed, a Persistent object is still stored in the database. The object is still a valid
Java object
and can be manipulated (have its data changed). But without a session, the Hibernate persistence
manager has
no way of synchronizing the data in the Persistent object with the database. These objects are no
longer part
of the persistence context.
Persistent objects become Detached objects when the session is closed. Calling session.evict() on the
object
reference or session.clear() will also remove an object from session. These later session operations will
be
covered later in class when cache is discussed.

Detached objects can be reassociated and synchronized to the database after a new session is opened.
Calling
session.update() or session.saveOrUpdate() on a Detached object reference transitions the Detached
object
back to the Persistent state. When a Detached object is reattached, the database is updated with
objects
current state; to include changes made while detached.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
transaction.commit();
session.close();
//p is now Detached
p.setNickname("Bambino"); //change is unsynchronized
session = sessionFactory.openSession();
transaction = session.beginTransaction();
//can also use session.saveOrUpdate() in method call below
session.update(p); //now new nickname is applied
transaction.commit();
session.close();

The Detached state may seem odd at first glance, but it provides an incredibly powerful capability to
applications. Applications could not (or should not) typically maintain long running transactions or
connections to a database. The effect of a long running transaction could be to create application
bottlenecks
that affectively keep other users from accomplishing work.

For example, think about the normal use and exchange of data in a Web application. A user may
request data
on a BallPlayer to be displayed on a Web page. The Web site fetches the BallPlayer data and displays it
in
HTML form. Later (who knows how much later could be a second or an hour), the user submits the
new

Player data to be saved back to the database. A Web application that opens a session and transaction
upon
request of the data and waits for submit to close/commit the unit of work has issues.

There is no telling when (if ever) the session/transaction will be closed in this circumstance. System
timeouts
will eventually cancel the transaction and close the connection to the database, but how long will that
take?
During that time, other users may not be able to access the BallPlayers data (or worse).

The Detached state allows Java objects to exist and to be used, but without a long running
session/transaction.
In the example just sited, open a session and transaction to load the BallPlayer object for display to the
user.
Then close the session/transaction. The BallPlayer object is still available for manipulation but without
ties
to the database. Open a new session/transaction and reattach the object when the user has submitted
the new
data.

Detatched objects keep sessions and related transactions short while still allowing for longer duration
work.
Deleted
To remove a Persistent object from the database call session.delete() on the object reference during a
session.
The delete() method has the affect of removing the row (or rows) associated with the Persistent object
from
the database.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
session.delete(p);
transaction.commit();
session.close();

If fact, the delete() method call causes Hibernate to issue an SQL delete command.

delete from Player where id=?

After calling delete() on the object, the object is no longer considered in the Persistent state as it is no
longer
represented in the database. However, it is a valid Java object. So what is it? So what state is it in?
The
object is back in a Transient state! It is as if the object was just created a new.

There is one caveat about the transition from the Persistent state to the Transient state. The identifier
in the
Persistent (and now Transient) object should be removed when deleted.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
session.delete(p);
transaction.commit();
session.close();
p.setId(null);

Why set the identifier to null? The answer is coming up.

For completeness, it is possible to delete a detached object.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
BallPlayer p = (BallPlayer)session.get(BallPlayer.class, 1L);
transaction.commit();
session.close();
//p is now Detached
session = sessionFactory.openSession();
transaction = session.beginTransaction();
session.delete(p);
transaction.commit();
session.close();

In effect, this is taking a detached object, reattaching it and then deleting it, but without the manual
call to
update().
Entities and Values
Hibernate distinguishes persistent objects into two types: entity types and value types.
Entity objects are first class persistent business objects. Entity objects have their own identity
(primary
key) in the database. Entity objects have their own lifecycle (covered in the last chapter). Objects can
have
relationships with other objects. For example, a Team object may be associated to one or more
BallPlayer
objects. When another object is associated to an entity instance the reference is persisted in a
database as a
foreign key (more on this later). BallPlayer objects are Entity types in Hibernate.

Value objects have no database identity.

Value objects belong to an owning entity object.

Value objects state is persisted in the table and row of the owning entity.

Value objects do not have an identifier (or identifier property).


The lifespan of a value type object is bound to the lifespan of the owning entity. Common value type
objects
include instances of String, Date, Integer, Long, etc.
Components
What do entity and value types have to do with relationships among domain model types?
First off, it is important to understand how objects such as Strings, Dates, etc. are handled in
Hibernate.
While still Java objects, these are not considered first-class objects. That is, they are not as
important from
a management standpoint. Secondly, understanding entity and value types is critical to understanding
the first
type of relationship in Hibernate: components.
Components are user-defined classes whose instances are persisted to the same table as an owning
entity.
Components are therefore considered value types in Hibernate. More precisely, components are
considered a
subset of value types.

Components look like any other Java class. They can have properties, like entity types. Like entity
types,
they must have a no-argument constructor. However, the properties of a component instance are
stored in the
table with the owning entity and identified by the owning entitys id. Take, for example, the
relationship
between a team and its manager (the head coach on a baseball team).

public class Team {


private long id;
private String nickname;
private Calendar founded;
private String mascot;
private Manager manager;
public Manager getManager() {
return manager;
}
public void setManager(Manager manager) {
this.manager = manager;
}
public Team(String nickname, Calendar founded, String mascot){
this.nickname=nickname;
this.founded=founded;
this.mascot=mascot;
}
public Team(){}
//getter/setter code removed for brevity
...

Every team has a manager.

public class Manager {


private String name;
private int yearStarted;
public Manager(String name, int yearStarted){
this.name=name;
this.yearStarted=yearStarted;
}
public Manager() {}
//getter/setter code removed for brevity
...

The Java Persistence specification calls components embedded classes, which may seem a more
appropriate
name.
When the manager object is a Component, the manager information is stored with the team data in
the Team
table.

Components, like other value types, do not have their own identifier. The component data is persisted
and
removed with its owning entity.
To map a component, use the <component> element in the owning entitys Hibernate mapping file.

<hibernate-mapping package="com.intertech.domain">
<class name="Team">
<id name="id">
<generator class="sequence">
<param name="sequence">common_seq</param>
</generator>
</id>
<property name="nickname" />
<property name="founded" />
<property name="mascot" />
<component name="manager" class="com.intertech.domain.Manager">
<property name="name" column="manager_name"/>

<property name="yearStarted" column="year_started" />


</component>
</class>
</hibernate-mapping>

No additional/separate mapping file is required for the Manager type.

To create and store a team object and its associated manager object, create both, associate the
manager to team
and save the team.

Calendar founded = Calendar.getInstance();


founded.set(1876, Calendar.APRIL, 25);
Team cubs = new Team("Cubs",founded,"Cubby Bear");
Manager mgr = new Manager("Lou Piniella", 2006);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
cubs.setManager(mgr);
session.save(cubs);
transaction.commit();
session.close();

This first type of association mapping also provides an opportunity to reinforce some of the basic
mapping
and Hibernate code requirements. Notice both Manager and Team need a default constructor. This is
required
by Hibernate of any Entity or Component. In fact, without a no-arguments constructor on Manager, the
code
above would throw an exception.

Exception in thread "main" org.hibernate.InstantiationException: No


default constructor for entity: com.intertech.domain.Manager
at
org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:
107)

For the code that creates and persists a Team and associated Manager to work, add the Team mapping
file as
a mapping resource declaration.

<hibernate-configuration>
<session-factory>
...
<mapping resource="com/intertech/domain/BallPlayer.hbm.xml" />
<mapping resource="com/intertech/domain/Team.hbm.xml" />
</session-factory>
</hibernate-configuration>

Or, when building the Configuration object, add the Tam class to the configuration.

new Configuration().configure().addClass(Team.class)

The column and type information for properties in the Component may be set by default (just as with
Entity
mapping). By default, the column name of a property is the same as the Components property name.
The type of a Components property is determined by reflection when not explicitly provided (just as
with
Entities). Attributes such as insert, update and access apply and can be used with Components just as
with
Entities. Components are allowed to have child components.
In the Team to Manager Component association above, the relationship is only one way or
unidirectional.
That is a Team has a Manager. The Component relationship can be made bidirectional. That is a
Manager can
have a Team. First, the Manger class would need to be modified to have/manage this relationship.

public class Manager {


private String name;
private int yearStarted;
private Team team;
public Team getTeam() {
return team;
}
public void setTeam(Team team) {
this.team = team;
}
...

Secondly, add a <parent> element to the <component> element in the mapping file to signify that
the
Component object knows its parent.

<component name="manager" class="com.intertech.domain.Manager">


<parent name="Team"/>
<property name="name" column="manager_name"/>
<property name="yearStarted" column="year_started" />
</component>

The name attribute on the parent must match the class name of the Entity that owns the Component
(in this
case Team).
When building and assembling the Java Entities and related Component objects, you must manage the
bidirectional relationship. That is, you must physically set the property on each object.

mgr.setTeam(cubs);
cubs.setManager(mgr);

When reading the Entity, however, Hibernate will create and reassemble the appropriate Component
object
and set the properties for you. Hibernate will re-associate in both directions when mapped as a
bidirectional
relationship. However, if all the properties of a component are null values, Hibernate does not create
and
reassemble the component. Instead, it sets the Entitys Component property to null. Therefore, it is
always a
good idea to check the Component property before using it after it has been read in/recreated from
the
database.

Team myTeam = (Team) session.get(Team.class, 9L);


if ((myTeam.getManager() != null) && (myTeam.getManager().getYearStarted()
> 2005)) {
//As long as there is data, no need to explicitly get Manager
} else {
//If there is no Manager data for the team, then null is used for
//the component
}

It is possible in Java to assign the same Component object to two Entities.

Calendar founded = Calendar.getInstance();


founded.set(1876, Calendar.APRIL, 25);
Team cubs = new Team("Cubs",founded,"Cubby Bear");
Calendar founded2 = Calendar.getInstance();
founded2.set(1998, Calendar.MARCH, 31);
Team rays = new Team("Rays",founded2, "Raymond");
Manager mgr = new Manager("Lou Piniella", 2006);
cubs.setManager(mgr);
rays.setManager(mgr);

While physically possible, this creates a logical problem in the database.

The same Manager data is now associated to two rows in the database. In fact, when read back in from
the
database, Hibernate will create two Manager Components each with the same data.

Session session = sessionFactory.openSession();


Transaction transaction = session.beginTransaction();
Team tm1 = (Team) session.get(Team.class, 14L);
Team tm2 = (Team) session.get(Team.class, 15L);
if (tm1.getManager()==tm2.getManager()){
System.out.println("These are the same object");
} else {
//This will always be the case unless tm1 and tm2
//are the same team
System.out.println("These are different objects");
}
transaction.commit();
session.close();

Remember, Components are owned by their Entity as far as Hibernate is concerned. There is no
identifier
that identifies Components or makes a Component unique. Therefore, a new Component is always
created
from the associated data with the Entity.

Components allow for a more fine-grained object model yet a more coarse-grained data model. The
composition association that Components provide, allow for reuse of the type across many classes.
The data
model may be denormalized but the reason for this choice is for better performance. Getting all teams
and
their manager in this case does not require a join.

DispatchAction provides a mechanism for grouping a set of related functions into a single
action, thus eliminating the need to create seperate actions for each functions. In this
example we will see how to group a set of user related actions like add user, update user
and delete user into a single action called UserAction.
The class UserAction extends org.apache.struts.actions.DispatchAction. This class does not
provide an implementation of the execute() method as the normal Action class does. The
DispatchAction uses the execute method to manage delegating the request to the individual
methods based on the incoming request parameter. For example if the incoming parameter
is "method=add", then the add method will be invoked. These methods should have similar
signature as the execute method.
view source
print ?

01.public class UserAction extends DispatchAction {


02.
03.private final static String SUCCESS = "success";
04.
05.public ActionForward add(ActionMapping mapping, ActionForm form,
06.HttpServletRequest request, HttpServletResponse response)
07.throws Exception {
08.UserForm userForm = (UserForm) form;
09.userForm.setMessage("Inside add user method.");

10.return mapping.findForward(SUCCESS);
11.}
12.
13.public ActionForward update(ActionMapping mapping, ActionForm form,
14.HttpServletRequest request, HttpServletResponse response)
15.throws Exception {
16.UserForm userForm = (UserForm) form;
17.userForm.setMessage("Inside update user method.");
18.return mapping.findForward(SUCCESS);
19.}
20.
21.public ActionForward delete(ActionMapping mapping, ActionForm form,
22.HttpServletRequest request, HttpServletResponse response)
23.throws Exception {
24.UserForm userForm = (UserForm) form;
25.userForm.setMessage("Inside delete user method.");
26.return mapping.findForward(SUCCESS);
27.}
28.}
If you notice the signature of the add, update and delete methods are similar to the execute
method except the name. The next step is to create an action mapping for this action
handler. The request parameter name is specified using the parameter attribute. Here the
request parameter name is method.
view source
print ?

1.<action-mappings>
2.<action input="/index.jsp" parameter="method" name="UserForm"path="/Us
erAction" scope="session" type="com.vaannila.UserAction">
3.<forward name="success" path="/index.jsp" />
4.</action>
5.</action-mappings>
Now lets see how to invoke a DispatchAction from jsp. We have a simple form with three
buttons to add, update and delete a user. When each button is clicked a different method in
UserAction class is invoked.
view source
print ?

01.<html>
02.<head>
03.<script type="text/javascript">
04.function submitForm()
05.{
06.document.forms[0].action = "UserAction.do?method=add"
07.document.forms[0].submit();
08.}
09.</script>
10.</head>

11.<body>
12.<html:form action="UserAction" >
13.<table>
14.<tr>
15.<td>
16.<bean:write name="UserForm" property="message" />
17.</td>
18.</tr>
19.<tr>
20.<td>
21.<html:submit value="Add" onclick="submitForm()" />
22.</td>
23.</tr>
24.<tr>
25.<td>
26.<html:submit property="method" value="update" />
27.</td>
28.</tr>
29.<tr>
30.<td>
31.<html:submit property="method" >delete</html:submit>
32.</td>
33.</tr>
34.</table>
35.</html:form>
36.</body>
37.</html>
Now consider the update and the delete button. The request parameter name specified in
the action handler is "method". So this should be specified as the property name for the
submit button. The name of the method to be invoked and the value of the button should be
the same. So when the button is clicked the corresponding method in the UserAction will be
called. The delete button shows an alternate way to specify the value of the button.
Here the main constraint is the method name and the button name should be same. So we
can't have an update button like this "Update". Inorder to avoid this you can call a javascript
function on click of the button. Specify the action and submit the form from javascript. In this
way we can have a different button name and method name. On click of the Add button the
action value is set to "UserAction.do?method=add" and the form is submitted from
javascript.
On executing the sample example the following page is displayed to the user.

After clicking the add button the following page is displayed.

You can download the source code of the DispatchAction example by clicking on the
Download link below.

You might also like