Escolar Documentos
Profissional Documentos
Cultura Documentos
All of
these problems originated because I was dealing with a mainframe database which I was trying to access using
Hibernate.
Consider the following situations.
Example 1: Integer Date Formats
Let's start with one of the most straight-forward oddities. Our database had a number of dates — year, month and
day information. Rather than create a column type of DATE, the database designers instead decided to use a
column type of Integer and stored values like 19950927 (to represent Sept. 27th, 1995).
Now, Hibernate can easily map an Integer column, but ultimately we wanted to be able to work with the type as a
Java Date object. The ugly way of dealing with the problem is to have two different sets of getters/setters, like
this:
public Integer getCreationDateAsInteger() {
return this.creationDate;
}
public Date getCreationDate() {
return DateUtil.convertIntegerToDate(this.creationDate);
}
Using this approach, we'd map the creationDateAsInteger property to the database column, and the other property
would not be mapped to a column. That works, but it has the minor disadvantage of cluttering up our code.
Instead, we created an IntegerDateUserType class like this:
public class IntegerDateUserType implements UserType {
Database tables that include blobs (and clobs) require special attention in Hibernate. The Java API for blobs allows
for read/write access to blob data using streams, but that API can only be invoked while the original
connection/statement is still open. In Hibernate terms, the original Hibernate Session must still be open.
In a lot of web architectures, this approach is problematic because developers often use Hibernate persistent
classes outside of the original Hibernate session.
I've used two primary strategies for handling blobs in Hibernate:
1. read the blob from the database and hold it as a byte array
2. lazily fetch the blob contents as required.
Both of these approaches have down-sides.
The primary down-side of the first approach relates to extremely large blob values. Consider, for example, a 1
Gigabyte movie file. Holding a 1 Gigabyte movie file as a byte array is going to take about a Gigabyte of RAM.
That's a lot of RAM; more than the typical memory allocation of a standard Java application.
The primay down-side of the second approach relates to updateability of the blob records. It becomes harder to
issue updates against a database record that includes a blob.
Let's try to describe these two approaches in more detail.
Blob to Byte Array
I've seen two common ways of handling the blob to byte array conversion:
1. use a pseudo-Blob property; and
2. use a blob user type.
Pseudo-Blob Property
The first strategy is fairly simple. Create a persistent bean, like so:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;
import org.hibernate.Hibernate;
try {
while((dataSize = is.read(buf)) != -1) {
baos.write(buf, 0, dataSize);
}
} finally {
if(is != null) {
is.close();
}
}
return baos.toByteArray();
}
}
Part of the trick to this class is that Hibernate is able to invoke private getters and setters to set properties. As a
result, the "label" and "blob" properties will be mapped to columns on the database table, while the "image"
property will not.
Instances of this class do not keep any reference to Blob object. It is only referenced during invocations of the
setBlob/getBlob calls. And because those methods are private, we're pretty much guaranteed that they'll only be
called by Hibernate in the context of a Session.
Blob user types are slightly more appealing than the above approach, as you can create a user type class that
encapsulates all the Hibernate ugliness and end up with a much cleaner-looking persistent class.
Here are two links for Blob User Types:
As someone fairly new to Hibernate, I was pleasantly surprised to see that it supported the execution of an SQL
query through the createSQLQuery() method within the Hibernate Session.
Initially, it seemed beneficial to use plain old SQL to generate my DAO queries. After all I already knew SQL, why
waste my time learning HQL (Hibernate's query language) or Hibernate's Criteria API. In addition, with SQL I could
easily test my queries in DB editing tool like DBVisualizer and in the ?rare? event that I might need it, a DBA
unfamiliar with Hibernate could easily enhance and maintain my queries.
It seemed like the solution.
However, on further analysis I have changed my tune.
There are many reasons from a purely OO point of view to avoid straight SQL. However, many other people make
a far more compelling argument on this point than I can here, so I'll leave that to them.
The main point I would like to focus on here is:
The Hibernate SQLQuery bypasses the Hibernate Session cache and queries ONLY against the database.
This means that if you perform a SQL query on the database in the same transaction that you've just
performed a save and/or update, the saved / updated objects in the Hibernate Session Cache will not
be included in the SQL result.
By the same token, HQL and the Hibernate Criteria queries check the Session cache before executing the query. If
there are objects that the HQL query may execute against hibernate will flush the cache to the database.
This essentially means that unlike the SQLQuery, HQL and Hibernate Criteria queries will ALWAYS
include the objects in the Session Cache automatically.
1) As noted on the SQLQuery diagram, you can actually manually force Hibernate to flush the cache by executing
session.flush(). This would require you to execute this line before each SQLQuery you execute. For instance:
session.flush();
List result = session.createSqlQuery("select name from user where name = :userName")
.setParameter("userName", user.getName())
.list();
However, this has two major disadvantages:
• You might accidently forget to do this, leaving your application in a poor state.
• session.flush() is an expensive operation. Using HQL and Criterias Hibernate can decide whether or not it
needs to flush. Thereby avoiding unnecessary flushing.
2) Junit testing.
It's worth mentioning that the code in the example diagrams are Junit tests. By utilizing hibernate's transaction
mechanism and the session cache we are able to test our dao code without actually changing the state of our
database. At the end of the test we can just rollback the transaction and undo any updates that we made.
Hibernate comes with three different caching mechanisms - first level, second level and query cache. Truly
understanding how the Hibernate caches work and interact with each other is important when you need to increase
performance - just enabling caching in your entity with an annotation (or in classic .hbm.xml mapping file) is easy.
But understanding what and how things happens behind the scenes is not. You might even end up with a less
The purpose of the Hibernate SessionFactory (called EntityManager in JEE) is to create Sessions, initialize JDBC
connections and pool them (using a pluggable provider like C3P0). A SessionFactory is immutable and built from a
Configuration holding mapping information, cache information and a lot of other information usually provided by
A Session is a unit of work at its lowest level - representing a transaction in database lingua. When a Session is
created and operations are done on Hibernate entities, e.g. setting an attribute of an entity, Hibernate does not go
of and update the underlying table immediately. Instead Hibernate keeps track of the state of an entity, whether it
is dirty or not, and flushes (commits) updates at the end at the end of a unit of work. This is what Hibernate calls
Definition: The first level cache is where Hibernate keeps track of the possible dirty states of the ongoing Session's
loaded and touched entities. The ongoing Session represents a unit of work and is always used and can not be
turned of. The purpose of the first level cache is to hinder to many SQL queries or updates beeing made to the
database, and instead batch them together at the end of the Session. When you think about the 1st level cache
think Session.
The 2nd level cache
The 2nd level cache is a process scoped cache that is associated with one SessionFactory. It will survive Sessions
and can be reused in new Session by same SessionFactory (which usually is one per application). By default the
The hibernate cache does not store instances of an entity - instead Hibernate uses something called dehydrated
state. A dehydrated state can be thought of as a deserialized entity where the dehydrated state is like an array of
strings, integers etc and the id of the entity is the pointer to the dehydrated entity. Conceptually you can think of it
as a Map which contains the id as key and an array as value. Or something like below for a cache region:
If the entity holds a collection of other entities then the other entity also needs to be cached. In this case it could
available, not aimed for production though). Hibernate instead has a plugin concept for caching providers which is
1 Cache Strategy. Enable a cache strategy for your Hibernate entity - either in the class with an annotation or in
the hibernate mapping xml file if you are stuck with pre java5. This can be done for an entity by providing this little
snippet into your hbm.xml file (a better place is to store the cache setting strategy in hibernate.cg.xml file )
<id ...
</class>
or using an annotation for your entity (if you are on java5 or greater)
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
And as mentioned above if you want to cache collections of an entity you need to specify caching on collection
level:
<cache usage="transactional|read-write|nonstrict-read-write|read-only"/>
<id ...
<set name="nodes">
<cache usage="transactional|read-write|nonstrict-read-write|read-only"/>
...
</set>
</class>
Hibernate has something called a cache region which by default will be the full qualified name of your Java class.
And if you like me are a fan of convention over configuration you will use the default region for an entity. A cache
region will also be needed for the collection using the full qualified name of the Java class plus the name of the
most common choice i dear to say - then you will need to specify some settings for the cache regions of your
entities in a file called ehcache.xml. The EHCache will look for this file in the classpath and if not found it will
fallback to ehcache-failsafe.xml which resides in the ehcache.jar library A typical sample for an EHCache
configuration could look like (see mind map below for explanations):
timeToLiveSeconds="600" overflowToDisk="false"/>
and
timeToLiveSeconds="600" overflowToDisk="false"/>
The name maps to the name of the cache region of your entity. The attribute maxelementsInMemory needs to be
set so that Hibernate does not have to swap in and out elements from the cache. A good choice for a read only
cache would be as many entities there are in the database table the entity represents. The attribute eternal, if set
to true means that any time outs specified will be ignored and entities put into the cache from Hibernate will live
for ever.
Below is a mindmap for the second level cache and how it relates to the SessionFactory and the 1st level cache.
The Query cache
The Query cache of Hibernate is not on by default. It uses two cache regions called
the query along with the parameters to the query as a key into the cache and the last one keeps track of stale
query results. If an entity part of a cached query is updated the the query cache evicts the query and its cached
result from the query cache. Of course to utilize the Query cache the returned and used entities must be set using
a cache strategy as discussed previously. A simple load( id ) will not use the query cache but instead if you have a
query like:
Hibernate will cache using as key the query and the parameters the value of the if of the entity.
{"from Router as r where r.id= :id and r.created = :creationDate", [ new Date() ] } ----> [ 4321 ] ]
How do you now if you are hitting the cache or not? One way is using Hibernates SessionFactory to get statistics
for cache hits. In your SessionFactory configuration you can enable the cache statistics by:
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
The you might want to write a unit test to verify that you indeed are hitting the cache. Below is some sample code
getSecondLevelCacheStatistics(cacheRegion);
stopWatch.start();
messageDAO.findAllMessages();
stopWatch.stop();
assertEquals(0, settingsStatistics.getMissCount());
assertEquals(numberOfMessages * i, settingsStatistics.getHitCount());
stopWatch.reset();
System.out.println(settingsStatistics);
endTransaction();
// spring creates a transaction when test starts - so we first end it then start a new in the loop
startNewTransaction();
}
transaction (1):
rollback = true
Number of rows :6
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk
=0,sizeInMemory=8814]
transaction
transaction (2):
rollback = true
Query time : 8
SecondLevelCacheStatistics[hitCount=6,missCount=0,putCount=6,elementCountInMemory=6,elementCountOnDisk
=0,sizeInMemory=8814]
transaction
transaction (3):
rollback = true
Query time : 11
Another way to spy on what Hibernate is doing is to proxy the jdbc driver used by a proxy driver. One excellent
one I use is p6spy which will show you exactly what is issued over a JDBC connection to the actual backend
same data without compromising the integrity and correctness of the data
and end it by calling commit(). You may, at any time, force an immediate
Hibernate automatically
In a system that stores data in multiple databases, you can’t achieve atomicity
using JDBC alone. JTA is also for declarative container managed transactions (CMT).
Transaction interface.
Transaction tx = null;
try {
tx = session.beginTransaction();
concludeAuction();
tx.commit();
} catch (Exception e) {
if (tx != null) {
try {
tx.rollback();
throw e;
} finally {
try {
session.close();
throw he;
The call to tx.commit() synchronizes the Session state with the database. Hibernate
If beginTransaction() did not start an underlying database transaction, commit() only synchronizes
the Session state with the database; it’s left to the responsible party (the
code that started the transaction in the first place) to end the transaction.
back by calling tx.rollback(). This method either rolls back the transaction
It’s critically important to close the Session in a finally block in order to ensure that
model made in the scope of a Session aren’t immediately propagated to the database.
FlushMode.AUTO
execution
ISOLATION ISSUES
Lost update—Two transactions both update a row and then the second transaction
Unrepeatable read—A transaction reads a row twice and reads different state
each time.
that two concurrent transactions both read a row, one writes to it and commits,
Phantom read—A transaction executes a query twice, and the second result
set includes rows that weren’t visible in the first result set.
ISOLATION LEVELS
Read uncommitted—Permits dirty reads but not lost updates. exclusive write locks.
Read committed—Permits unrepeatable reads but not dirty reads. momentary shared read locks and exclusive
write locks.
write locks.
cache and versioning already gives you most of the features of repeatable read
isolation.
Hibernate will then set this isolation level on every JDBC connection obtained from
A pessimistic lock is a lock that is acquired when an item of data is read and that
The Hibernate LockMode class lets you request a pessimistic lock on a particular
item. In addition, you can use the LockMode to force Hibernate to bypass the cache
Transaction tx = session.beginTransaction();
Category cat =
cat.setName("New Name");
tx.commit();
With this mode, Hibernate will load the Category using a SELECT...FOR UPDATE,
thus locking the retrieved rows in the database until they’re released when the
transaction end
UPDATE NOWAIT on Oracle. his disables waiting for concurrent lock releases,
to bypass both levels of the cache and go all the way to the database.
transaction currently
Business processes, which might be considered a single unit of work from the point
timestamp that is updated to the current time, every time an object is modified
modified.
Hibernate managed versioning, we must add a new property to our Comment class
<id ...
...
</class>
...
...
this.lastUpdatedDatetime = lastUpdatedDatetime;
return lastUpdatedDatetime;
<id ...../>
...
</class>
If another application transaction would have updated the same item since it was
read by the current application transaction, the VERSION column would not contain
the value 2, and the row would not be updated. Hibernate would check the row
count returned by the JDBC driver—which in this case would be the number of
GRANULARITY OF A SESSION
the client
The session (S1) and the database transaction (T1) therefore have the same
granularity.
cycles—for example, two HTTP requests in a web application. You could load the
interesting objects in a first Session and later reattach them to a new Session after
they’ve been modified by the user. Hibernate will automatically perform a version
check.
Alternatively, you might prefer to use a single Session that spans multiple
A Session is serializable and may be safely stored in the servlet HttpSession, for
example. The underlying JDBC connection has to be closed, of course, and a new
and reconnect() methods of the Session interface to release the connection and
later obtain a new connection. The longer the session remains open, the greater the chance that it holds stale data
in its cache of persistent objects
<id ...../>
...
</class>
Hibernate will include only the modified properties if you set optimistic-lock="dirty"
than version numbers and doesn’t work if your application transaction spans multiple
sessions
Transaction scope+
Process scope
Cluster scope
Any ORM implementation that allows multiple units of work to share the same persistent
always active—it’s used to resolve circular references in your object graph and to
The session cache ensures that when the application requests the same persistent
object twice in a particular session, it gets back the same Java instance.
that object is added to the session cache. When flush() is subsequently called, the
evict() method of the Session to remove the object and its collections from the
first-level cache.
USING SECOND LEVEL CACHE
level cache on the other hand is optional and works best for read-mostly candidate
classes.
If you have data that is updated more often than it’s read, don’t
enable the second-level cache, even if all other conditions for caching are true!
net.sf.hibernate.cache.CacheConcurrencyStrategy,
the second-level cache for a particular class if stale data isn’t an option.
Hibernate forces you to choose a single cache provider for the whole
application.
EHCache
OpenSymphony OSCache
SwarmCache s.
JBossCache
CACHING IN PRACTICE
<class
name="Category"
table="CATEGORY">
<cache usage="read-write"/>
<id ....
</class>
<class
name="Category"
table="CATEGORY">
<cache usage="read-write"/>
<id ....
<cache usage="read-write"/>
<key ....
</set>
</class>
<class
name="Item"
table="ITEM">
<cache usage="read-write"/>
<id ....
<cache usage="read-write"/>
<key ....
</set>
</class>
<class
name="Bid"
table="BID">
<cache usage="read-only"/>
<id ....
</class>
Cached Bid data is valid indefinitely, because bids are never updated. No cache
invalidation is required.
is a named cache: a handle by which you can reference classes and collections in
the cache provider configuration and set the expiration policies applicable to
that region.
The name of the region is the class name, in the case of a class cache; or the class
name together with the property name, in the case of a collection cache. Category
items.
hibernate.cache.provider_class=net.sf.ehcache.hibernate.Provider
regions.
EHCache has its own configuration file, ehcache.xml, in the classpath of the application.
<cache name="org.hibernate.auction.model.Category"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
a cache size limit greater than the number of categories in our system and setting
eternal="true".
<cache name="org.hibernate.auction.model.Bid"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="100000"
overflowToDisk="false"
/>
Hybernate aims to be a complete solution to the problem of managing persistent data in Java
Relational Technology allows to share data among different applications or among different
OBJECT-ORIENTED PERSISTENCE
A transient object has a limited life that is bounded by the process that instantiated it.
sorting, searching and aggregation of data. Database management systems are responsible for managing
concurrency and data integrity, and share data between multiple users and applications.
So Persistence means:
Data sharing
We think of these problems in the context of an object-oriented application that uses a domain model.
The business logic interacts with the object-oriented domain model and its runtime realization as a graph
of interconnected objects.
PARADIGM MISMATCH
Adding a UDT (User Defined Column-Type) to a SQL Table, like Address in the Table User, is not portable
and obscure
Classes come in the database in a range of different levels of granularity, coarse-grained like User,
finer-grained like Address, simple String-valued like zipcode. Just two levels of granularity in the
Some persistence mechanisms force the less flexible mechanism, like having the property zipcode in the
class User
INHERITANCE
POLYMORPHISM
SQL Database don't provide a notion of inheritance. A foreign key refers to a single table
OBJECT IDENTITY
Two (non-identical) objects may represent the same row on the database
OO languages represent associations using object references and collections of object references.
For SQL , an association is represented as a foreign key column, with copies of key in several tables.
OO reference are directional, the association must be defined twice if it needs be navigate in both
directions. FK are not directional since you can create arbitrary data associations with joins and projections.
Java associations may be many-to-many (Set in both objects). Table associations are always one-to-many or
one-to-one
Link table to represent a many-to-many associations in a relational database, which does not appear anywhere
Walking the object graph : navigate from one object to another, following associations between instances
To minimize the number of requests to the database, you need to join tables using SQL.
We need to know the portion of the object graph we plan to access before we start navigating the
object graph
N+1 selects problem : execute a select statement for every node in the graph. Any object persistence solution
provides functionality for accessing the data only when the object is first accessed.
Mismatch cost :
30% of the application code is written to handle the SQL / JDBC mismatch
JDBC's Statement -oriented approach to move data to and from the database. A structural relationship must
PERSISTENCE LAYER
Layered architecture
It defines interfaces between code that implements the various concerns, allowing a change to the way one
Layer communicate top to bottom. The only layer one layer is aware of is the one below it
Business model may use its domain model or reuse the one defined by the persistence model.
HandCoding SQL
Serialization
Setialized graph of interconnected object can only be accessed as a whole, so it is unusable for arbitrary
search or aggregation. Loading and overwriting and entire object in each transaction is no option for systems
EJB
Entity beans are not serializable, so we need to define a parallel domain model (DTOs)
OODBMS
Back-end data store, object cache and client application coupled tightly and communicating via a proprietary
network protocol
object oriented database development begins with the top-down definition of host language bindings that add
JDO opened up new possibilities . Niche markets : CAD / CAM and scientific computing.
XML persistence
Stored procedures
ORM is the automated persistence of objects in a Java application to the table in a relational database, using
metadata that describes the mapping between the objects and the database.
API for specifying queries that refer to classes and properties of classes
Technique to interact with transactional objects to perform dirty checking, lazy association fetching,
and other optimization techniques
With ORM the application interacts with the ORM APIs and
SQL / JDBC. ORM may take responsibility for optimistic locking and caching.
Light object mapping : Entities are represented as classes that are mapped manually to the relational tables
Medium object mapping : Application is designed around an object model. SQL is generated using code generation
or at runtime by framework code. Associations between object are supporte dby the persistence mechanism and
queries may be specified using an object oriented expression language. Objects are cached by the persistence
layer.
Full object mapping : supports sophisticated object modelling : composition, inheritance, polymorphism.
The persistent layer implements transparent persistence: persistent classes do not inherit any special object
or implement a special interface. Efficient fetching strategies are implemented transparently to the application.
Orm Problems :
How does the persistence logic interact at runtime with the object of business domain ?
ORM provides a buffer between the two models (object orientation and relational database)
Vendor Independence :
Transaction tx = session.beginTransaction();
session.save(message);
tx.commit();
session.close();
It will result in the execution of an INSERT sql statement . The id is in identifier property in Message, it
Transaction tx = session.beginTransaction();
tx.commit();
session.close();
Hybernate Query Language
<hibernate-mapping>
<class
name="hello.Message"
table="MESSAGES"
>
<id
name="id"
column="MESSAGE_ID">
<generator class="increment"/>
</id>
<property
name="text"
column="MESSAGE_TEXT">
</property>
<many-to-one
name="nextMessage"
cascade="all"
column="NEXT_MESSAGE_ID"/>
</class>
</hibernate-mapping>
Hybernate has all the information that is needed to insert / update / delete instances of the Message class.
Transaction tx = session.beginTransaction();
message.setText("Bla Bla");
Message nextMessage = new Message("Take me to your leader");
message.setNextMessage(nextMessage);
tx.commit();
session.close();
Cascading save : it saves us the effort of making an object persistent as long as it is reachable by an
Transactional write-behind : efficient ordering that avoid database foreign key violations
HYBERNATE INTERFACES
HYBERNATE INTERFACES
Callback allow the application to react to events occurring inside Hybernate : Interceptor, Lifecycle, Validatable
Existing APIS :
JTA, JNDI
CORE INTERFACES :
Store and retrieve persistent objects
Session is a persistence manager because is the interface for storing and retrieving
caches SQL statements and other mapping metadata which is used at runtime
May hold cached data which has been used in a unit of work and may be reused in another unit of work
the application uses the configuration interface to specify the location of mapping documents and
Query and Criteria : Query perform queries against the database and control how the query is executed.
Session has some lightweight methods to perform queries without using the interface Query
Query is lightweight and cannot be used outside the Session that created it
Callback : LifeCycle and Validatable allow a persistent object to react to events relating to its own
persistent lifecycle, which is encompassed by an object's crud operations. They should be implemented
Interceptor allows the application to process callbacks without forcing the persistent classes to
Type : a type maps a Java type to a database. All persistent properties of persistent classes, including
associations, have a corresponding Hybernate type.
You may add commonly used new application classe like Address, Name, MoneyAmount
EXTENSION INTERFACES :
IdentifierGenerator
Dialect
Cache / CacheProvider
ConnectionProvider
ClassPersister
PropertyAccessor
ProxyFactory
BASIC CONFIGURATION
MANAGED ENVIRONMENT : Pools Resources such as database connections and allows transactions boundaries
NON MANAGED : Basic concurrency management via thread pooling. Tomcat or stand-alone application
cfg.addResource("hello/Message.hbm.xml");
cfg.setProperties(System.getProperties());
Method Chaining
.addResource("hello/Message.hbm.xml")
.setProperties(System.getProperties())
.buildSessionFactory();
Mapping file for each class should be placed in the same directory as the class.
If files are named as the Class plus .hbm.xml you can use the addClass method instead
.addClass(org.hybernate.auction.model.Item.class)
.setProperties(System.getProperties()
.buildSessionFactory();
Each Session Factory is available for one database and ready to produce Sessions to work with that particular
Of all the configuration options, database settings are the most important.
hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/auctiondb
hibernate.connection.username = auctionuser
hibernate.connection.password = secret
hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=300
hibernate.c3p0.max_statements=50
hibernate.c3p0.idle_test_period=3000
hibernate.connection.datasource = java:/comp/env/jdbc/AuctionDB
hibernate.transaction.factory_class = \
net.sf.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
net.sf.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = net.sf.hibernate.dialect.PostgreSQLDialect
Two steps then (set the factory, set the manager lookup class)
ADVANCED CONFIGURATION SETTINGS
<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">
net.sf.hibernate.dialect.PostgreSQLDialect
</property>
<property name="transaction.manager_lookup_class">
net.sf.hibernate.transaction.JBossTransactionManagerLookup
</property>
<mapping resource="auction/Item.hbm.xml"/>
<mapping resource="auction/Category.hbm.xml"/>
<mapping resource="auction/Bid.hbm.xml"/>
</session-factory>
</hibernate-configuration>
.configure("/hibernate-config/auction.cfg.xml")
.buildSessionFactory();
JNDI-bound SessionFactory
The Java Naming and Directory Interface (JNDI) API allows objects to be
user registries), and even application objects (EJB references, object factories)
The SessionFactory will automatically bind itself to JNDI if the property hibernate.
environment doesn’t provide a default JNDI context (or if the default JNDI
jndi.class.
LOGGING
asynchronously. Instead, the SQL statements are usually issued at the end of a
JMX
¦ The (usually generic) JMX client—May be used to administer any MBean via
cross-cutting concerns in the classes that implement the domain model. When these
concerns start to appear in the domain model classes, we call this an example of
leakage of concerns.
Hibernate is commonly used together with the well-known session façade J2EE pattern.
data store; they need not even be aware that they are being persisted or
interface —in the case of Hibernate, the Session and Query interfaces.
java.util.HashSet
POJOS
constructor, Hibernate
public Category() { }
...
aChild.setParentCategory(aParent);
aParent.getChildCategories().add(aChild);
It’s a good idea to add a convenience method to the Category class that groups
if (childCategory == null)
if (childCategory.getParentCategory() != null)
childCategory.getParentCategory().getChildCategories()
.remove(childCategory);
childCategory.setParentCategory(this);
childCategories.add(childCategory);
In the case of a many-to-many association, both sides are implemented with collection-
valued attributes.
Hibernate will later use our accessor methods to populate the state of
an object when loading the object from the database. Sometimes we would prefer
that this validation not occur when Hibernate is initializing a newly loaded object.
In that case, it might make sense to tell Hibernate to directly access the instance
forcing Hibernate to bypass the setter method and access the instance variable
directly.
object state changes in order to synchronize the updated state with the database.
It’s usually completely safe to return a different object from the getter method to
the object passed by Hibernate to the setter. Hibernate will compare the objects
needs to be updated.
METADATA IN HYBERNATE
The metadata format is extremely readable and defines useful default values. When
attribute values are missing, Hibernate uses reflection on the mapped class to
<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>
have a primary key value that matches the object identity of the instance in memory.
practice expected by some Hibernate tools) is to use one mapping file per persistent
class.
column name, and the name of a Hibernate type. It maps a JavaBean style
<column name="DESCRIPTION"/>
</property>
<property name="totalIncludingTax"
type="big_decimal"/>
<property
name="averageBidAmount"
type="big_decimal"/>
<property name="name"
column="NAME"
type="string"
access="field"/>
means you are using the field to acccess and not the property.
access attribute if neither property nor field accessor is right for you
<property name="name"
column="NAME"
type="string"
insert="false"
update="false"/>
The property name of the JavaBean is therefore immutable and can be read from
the database but not modified in any way. If the complete class is immutable, set
<class name="org.hibernate.auction.model.User"
dynamic-insert="true"
dynamic-update="true">
...
</class>
<property name="description"
column="`Item Description`"/>
NAMING CONVENTIONS
SQL SCHEMA
Schema is a namespace
PACKAGE
You can specify a package in the hibernate-mapping tag if you don't want to repeat it anytime you
Once a SessionFactory is created, its mappings are immutable. In fact, the SessionFactory
uses a different metamodel internally than the one used at configuration time.
change the identifier value of a persistent instance after it’s first assigned.
part of the definition of a primary key is that its value should never
change.
The property type depends on the primary key type of the CATEGORY table and the
<generator class="native"/>
</id>
...
</class>
you may now use a.getId().equals( b.getId() ) to test database identity.
<id column="CATEGORY_ID">
<generator class="native"/
</id>
The candidate key is a column or set of columns that uniquely identifies a specific
and hence no candidate keys, then the table is by definition not a relation
long run.
identity
sequence
increment
hilo
uuid.hex
its persistent state is embedded in the table row of the owning entity).
Hibernate uses the term component for a user-defined class that is persisted to
<class
name="User"
table="USER">
<id
name="id"
column="USER_ID"
type="long">
<generator class="native"/>
</id>
<property
name="username"
column="USERNAME"
type="string"/>
<component
name="homeAddress"
class="Address">
<property name="street"
type="string"
column="HOME_STREET"
notnull="true"/>
<property name="city"
type="string"
column="HOME_CITY"
not-null="true"/>
<property name="zipcode"
type="short"
column="HOME_ZIPCODE"
not-null="true"/>
</component>
<component
name="billingAddress"
class="Address">
<property name="street"
type="string"
column="BILLING_STREET"
notnull="true"/>
<property name="city"
type="string"
column="BILLING_CITY"
not-null="true"/>
<property name="zipcode"
type="short"
column="BILLING_ZIPCODE"
not-null="true"/>
</component>
...
</class>
<parent name="user"/>
it doesn’t support polymorphic associations very well. if the subclasses are all mapped to different
table would include columns for all properties of all classes in the hierarchy. The
<hibernate-mapping>
<class
name="BillingDetails"
table="BILLING_DETAILS" discriminator-value="BD">
<id
name="id"
column="BILLING_DETAILS_ID"
type="long">
<generator class="native"/>
</id>
<discriminator
column="BILLING_DETAILS_TYPE"
type="string"/>
<property
name="name"
column="OWNER"
type="string"/>
...
<subclass
name="CreditCard"
discriminator-value="CC">
<property
name="type"
column="CREDIT_CARD_TYPE"/>
...
</subclass>
...
</class>
</hibernate-mapping>
TABLE PER SUBCLASS
The table here contains columns only for each non-inherited property along
with a primary key that is also a foreign key of the superclass table.
mapping
<joined-subclass
name="CreditCard"
table="CREDIT_CARD">
<key column="CREDIT_CARD_ID">
<property
name="type"
column="TYPE"/>
...
</joined-subclass>
our
<class
name="Bid"
table="BID">
...
<many-to-one
name="item"
column="ITEM_ID"
class="Item"
not-null="true"/>
</class>
...
this.bids = bids;
return bids;
bid.setItem(this);
bids.add(bid);
...
<class
name="Item"
table="ITEM">
...
<set name="bids">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
<class
name="Item"
table="ITEM">
...
<set
name="bids"
inverse="true">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
bid.setItem(item);
bids.add(bid);
Without the inverse attribute, Hibernate would try to execute two different SQL
statements, both updating the same foreign key column, when we manipulate the
at the Bid end of the association to the database, ignoring changes made only to
<class
name="Item"
table="ITEM">
...
<set
name="bids"
inverse="true"
cascade="save-update">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
The cascade attribute tells Hibernate to make any new Bid instance persistent
(that is, save it in the database) if the Bid is referenced by a persistent Item.
<class
name="Item"
table="ITEM">
...
<set
name="bids"
inverse="true"
cascade="save-update">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
The cascade attribute tells Hibernate to make any new Bid instance persistent
(that is, save it in the database) if the Bid is referenced by a persistent Item.
If we enable cascading delete, the association between Item and Bid is called a
parent/child relationship.
is that the child may be loaded individually or referenced directly by another entity.
<class
name="Item"
table="ITEM">
...
<set
name="bids"
inverse="true"
cascade="all-delete-orphan">
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
</class>
persistent Item
Any persistent Bid should be deleted if it’s removed from the bids collection
of a persistent Item
Transient
Persistent
A persistent instance is any instance with a database identity. Persistent instances might
be objects instantiated by the application and then made persistent by calling the save()
which persistent objects have been modified by the application in the transaction.
transparent transaction-level write-behind : Hibernate propagates state changes to the database
DETACHED OBJECTS
It’s possible for the application to retain a reference to a detached object outside of
The application can control the depth of the fetched subgraph using the query language or
explicit graph navigation. Then, when the Session is closed, this entire subgraph
becomes detached.
if a row is accessed twice, the same Java object instance will be returned to
different instances that both represent the same row in a single transaction
context of a single transaction, there is only one object instance that represents
one object instance representing the row in the whole process (JVM).
If you request two objects using the same database identifier value in the
same Session, the result will be two references to the same in-memory object.
if ( a==b ) {
tx1.commit();
session1.close();
if ( a!=b2 ) {
tx2.commit();
session2.close();
a and b are equal at first but not after b is fetched from the second session
Selective reassociation of detached instances :
EQUALS
Default implentation of EQUALS is mostly broken if you happen to mix instances of different
sessions
Has a problem since identifier change values during the object lifetime
return id==null ?
System.identityHashCode(this) :
id.hashCode();
}
COMPARING BY VALUE
We don’t mean to include collections : important, you don’t want to force the entire object graph
Problems :
Instances with different database identity could be considered equal, unless there is some
each instance with the same database identity. Essentially, it’s the natural key you’d
tEvery entity should have a business key, even if it includes all properties
of the class
Business key equality means that the equals() method compares only the properties
the properties of the other object via the getter methods. the object instance
Session is your starting point for all the operations just listed.
User user = new User();
user.getName().setFirstname("John");
user.getName().setLastname("Doe");
Transaction tx = session.beginTransaction();
session.save(user);
tx.commit();
session.close();
It’s better (but not required) to fully initialize the User instance before
All database operations in a transaction scope either completely succeed or completely fail.
The update() method forces an update to the persistent state of the object in
user.setPassword("secret");
Transaction tx = sessionTwo.beginTransaction();
sessionTwo.update(user);
user.setUsername("jonny");
tx.commit();
sessionTwo.close();
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).
A call to lock() associates the object with the Session without forcing an update,
Transaction tx = sessionTwo.beginTransaction();
sessionTwo.lock(user, LockMode.NONE);
user.setPassword("secret");
user.setLoginName("jonny");
tx.commit();
sessionTwo.close();
you only use lock() if you’re sure that the detached instance
Hibernate lock modes : NONE (no version check), READ / UPGRADE (A select statement is
Transaction tx = session.beginTransaction();
tx.commit();
session.close();
Any persistent object returned by get() or any other kind of query is already associated
with the current Session and transaction context. It can be modified, and
its state will be synchronized with the database. This mechanism is called automatic
dirty checking, which means Hibernate will track and save the changes you make to
Transaction tx = session.beginTransaction();
user.setPassword("secret");
tx.commit();
session.close();
Transaction tx = session.beginTransaction();
session.delete(user);
tx.commit();
session.close();
The SQL DELETE will be executed only when the Session is synchronized with the
You can make a detached instance transient, deleting its persistent state
session.delete(user);
tx.commit();
session.close();
a more natural way to force object state changes and to control the persistence
lifecycle.
Persistence by reachability :
mapping, which offers more flexibility and fine-grained control for all state transitions.
objects automatically.
update() and save newly instantiated transient instances and persist changes to
detached instances.
Hibernate deletes any persistent entity instance that has been removed
¦ cascade="delete-orphan" Hibernate will delete any persistent entity
instance that has been removed (dereferenced) from the association (for
relational database. It allows Hibernate applications to use detached objects efficiently, because you can
...
<many-to-one
name="parentCategory"
class="Category"
column="PARENT_CATEGORY_ID"
cascade="none"/>
<set
name="childCategories"
table="CATEGORY"
cascade="save-update"
inverse="true">
<key column="PARENT_CATEGORY_ID"/>
<one-to-many class="Category"/>
</set>
...
</class>
Transaction tx = session.beginTransaction();
computer.getChildCategories().add(laptops);
laptops.setParentCategory(computer);
tx.commit();
session.close();
association has cascade save enabled. Hence, this code results in the new
computer.getChildCategories().add(laptops);
laptops.setParentCategory(computer);
session:
Transaction tx = session.beginTransaction();
// Persist one new category and the link to its parent category
session.save(laptops);
tx.commit();
session.close();
reflects the fact that Hibernate determines what is needed to persist the objects to
to the database by creating a new database row if the instance is a new transient
You have to let Hibernate know how to distinguish between a detached instance like laptops (if it
was created in a previous session) and a new transient instance like laptopBags
You supply an unsaved-value in the mapping document for the class, and
<generator class="native"/>
</id>
....
</class>
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
RETRIEVING OBJECTS
nodes of the graph while you navigate the graph if the Session is open.
query language.
-Using the, Hibernate Criteria API, which provides a type-safe and objectoriented
-Using native SQL queries, where Hibernate takes care of mapping the JDBC
-The goal is to find the best retrieval method and fetching strategy for every use case in your
application while at the same time minimizing the number of SQL queries for
best performance.
Objects by Identifier :
thrown. The load() method never returns null. The get() method returns
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; we discuss proxies later in this section. On the
If you’re certain the persistent object exists, and nonexistence would be considered exceptional,
load() is a good option. The application may retrieve a valid reference (a proxy) to a
persistent instance without hitting the database to retrieve its persistent state.
INTRODUCING HQL
retrieval
q.setString("fname", "Max");
Aggregation with group by, having, and aggregate functions like sum, min,
and max.
QUERY BY CRITERIA
The Hibernate query by criteria (QBC) API lets you build a query by manipulating criteria
without direct string manipulations, but it doesn’t lose much of the flexibility or
power of HQL.
A Criteria is a tree of Criterion instances. The Expression class provides static factory
methods that return Criterion instances. Once the desired criteria tree is
They also like the fact that the query syntax may be parsed and validated at compile
The nice thing about the Hibernate Criteria API is the Criterion framework.
This framework allows extension by the user, which is difficult in the case of a query
QUERY BY EXAMPLE
Hibernate supports query by example (QBE). The idea
behind QBE is that the application supplies an instance of the queried class with
exampleUser.setFirstname("Max");
criteria.add( Example.create(exampleUser) );
FETCHIN STRATEGIES
One of the most difficult problems in ORM is providing for efficient access to relational data, given an application
Hibernate allows you to choose among four fetching strategies for any association,
it’s first accessed. This results in a new request to the database (unless the
Lazy fetching lets you decide how much of the object graph is loaded in the first
database hit and which associations should be loaded only when they’re first
accessed.
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.
is accessed.
We can even
choose any interface implemented by the Item class as the type of the proxy.
fetches the associated object lazily if the associated class has proxying
an outer join, even if proxying is enabled. This allows you to choose different
COLLECTIONS
In the case of collections, fetching strategies apply not just to entity associations,
Just like classes, collections have their own proxies, which we usually call collection
wrappers. Unlike classes, the collection wrapper is always there, even if lazy fetching
is disabled
neither, or both
Neither attribute specified :The collection is fetched from the second-level cache or by
accessed.
<key column="ITEM_ID"/>
<one-to-many class="Bid"/>
</set>
many-to-many associations You usually use a link table that holds only the key values of the two
associated tables and therefore allows a many-to-many multiplicity. This additional
<key column="CATEGORY_ID"/>
</set>
In this case, the eager fetching strategy refers only to the association table
automatically fetch all link entries from CATEGORY_ITEM in a single outer join SQL
<key column="CATEGORY_ID"/>
</set>
Hibernate will now fetch all Items in a Category with a single outer join query when
Hibernate’s outer join fetch behavior is controlled with the global configuration
will fetch only the Category and the link entries from the CATEGORY_ITEM association
table. If you set it to 2, Hibernate executes an outer join that also includes
are invoked (except the identifier property getter, which may return the identifier
open Session. If you close the session and try to access an uninitialized proxy or
Transaction tx = session.beginTransaction();
Hibernate.initialize( cat.getItems() );
tx.commit();
session.close();
a proxy. You may also, in similar rare cases, check the current state of a property by
calling Hibernate.isInitialized().
Step through your application use case by use case and note how many
HYBERNATE TYPES
identity. A value type is a class that doesn’t define some kind of persistent identity.
At runtime, you have a graph of entity instances interleaved with value type
instances. The entity instances may be in any of the three persistent lifecycle states:
entities. This means that a value type instance is owned by exactly one entity
Hibernate’s built-in mapping types usually share the name of the Java type they
map
MAPPING_TYPES :
integer
long
short
float
double
big_decimal
character
string
byte
boolean
yes_no
true_false
date
time
timestamp
calendar
calendar_date
binary
text
serializable
clob
blob
class
locale
timezone
currency
<class name="BillingDetails"
table="BILLING_DETAILS"
discriminator-value="null">
<generator class="native"/>
</id>
...
</class>
It’s often not necessary to explicitly specify a built-in mapping type in the XML
java.lang.String, Hibernate will discover this using reflection and select string
by default.
The most important case where this approach doesn’t work well is a
.list();
net.sf.hibernate.UserType.
this.value = value;
this.currency = currency;
package auction.customtypes;
import ...;
if (x == y) return true;
return x.equals(y);
String[] names,
Object owner)
Object value,
int index)
statement.setNull(index, Types.NUMERIC);
} else {
MonetaryAmount amountInUSD =
MonetaryAmount.convert( anyCurrency,
Currency.getInstance("USD") );
statement.setBigDecimal(index, amountInUSD.getValue());
<property name="initialPrice"
column="INITIAL_PRICE"
type="auction.customtypes.MonetaryAmountUserType"/>
package auction.customtypes;
import ...;
implements CompositeUserType {
if (x == y) return true;
return x.equals(y);
String[] names,
SessionImplementor session,
Currency currency =
Object value,
int index,
SessionImplementor session)
if (value==null) {
statement.setNull(index, Types.NUMERIC);
statement.setNull(index+1, Types.VARCHAR);
} else {
String currencyCode =
amount.getCurrency().getCurrencyCode();
}
public Type[] getPropertyTypes() {
int property)
throws HibernateException {
if (property == 0)
return MonetaryAmount.getValue()();
else
return MonetaryAmount.getCurrency();
int property,
SessionImplementor session,
Object owner)
throws HibernateException {
return cached;
SessionImplementor session)
throws HibernateException {
}
<property name="initialPrice"
type="auction.customtypes.MonetaryAmountCompositeUserType">
<column name="INITIAL_PRICE"/>
<column name="INITIAL_PRICE_CURRENCY"/>
</property>
from Item i
ENUMERATED TYPES
An enumerated type is a common Java idiom where a class has a constant (small)
package auction;
static {
INSTANCES.put(EXCELLENT.toString(), EXCELLENT);
INSTANCES.put(OK.toString(), OK);
INSTANCES.put(LOW.toString(), LOW);
this.name=name;
}
return name;
Object readResolve() {
return getInstance(name);
package auction.customtypes;
import ...;
String[] names,
Object owner)
Object value,
int index)
throws HibernateException, SQLException {
if (value == null) {
statement.setNull(index, Types.VARCHAR);
} else {
statement.setString(index, value.toString());
Query q =
q.setParameter("rating",
Rating.LOW,
Hibernate.custom(RatingUserType.class));
...
return this.images;
this.images = images;
<key column="ITEM_ID"/>
</set>
The <key> element
declares the foreign key, ITEM_ID of the parent entity. The <element> tag declares
A set can’t contain duplicate elements, so the primary key of the ITEM_IMAGE
table consists of both columns in the <set> declaration: ITEM_ID and FILENAME.
Changing the table definition from the previous section to permit duplicate FILENAMEs
<generator class="sequence"/>
</collection-id>
<key column="ITEM_ID"/>
</idbag>
A <list> mapping requires the addition of an index column to the database table.
The index column defines the position of the element in the collection.
Hibernate can preserve the ordering of the collection elements when retrieving
<key column="ITEM_ID"/>
<index column="POSITION"/>
</list>
Mapping a <map> (pardon us) is similar to mapping a list:
<key column="ITEM_ID"/>
</map>
<map name="images"
lazy="true"
table="ITEM_IMAGE"
sort="natural">
<key column="ITEM_ID"/>
</map>
<set name="images"
lazy="true"
table="ITEM_IMAGE"
sort="natural">
<key column="ITEM_ID"/>
</set>
<set name="images"
lazy="true"
table="ITEM_IMAGE"
sort="natural">
<key column="ITEM_ID"/>
<idbag name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="ITEM_IMAGE_ID desc">
<generator class="sequence"/>
</collection-id>
<key column="ITEM_ID"/>
</idbag>
<set name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<key column="ITEM_ID"/>
<composite-element class="Image">
< /composite-element>
</set>
BIDIRECTIONAL NAVIGATION
The association from Item to Image is unidirectional. If the Image class also
declared a property named item, holding a reference back to the owning Item,
<set name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<key column="ITEM_ID"/>
<composite-element class="Image">
<parent name="item"/>
</composite-element>
</set>
<idbag name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<generator class="sequence"/>
</collection-id>
<key column="ITEM_ID"/>
<composite-element class="Image">
</composite-element>
</idbag>
<composite-element class="Image">
</composite-element>
</map>
This time, the primary key is the ITEM_IMAGE_ID column, and it isn’t important that
we implement equals() and hashCode() (at least, Hibernate doesn't require it).
We should point out that there isn’t a great deal of difference between this bag
When we use the word associations, we’re always referring to relationships between
entities.One-to-many associations are easily the most important kind of association. In
<generator class="native"/>
</id>
<property name="street"/>
<property name="city"/>
<property name="zipcode"/>
</class>
The easiest way to represent the association from User to its billingAddress is to
<many-to-one name="billingAddress"
class="Address"
column="BILLING_ADDRESS_ID"
cascade="all"
unique="true"/>
<one-to-one name="user"
class="User"
property-ref="billingAddress"/>
address.setCity("Toorak");
address.setZipcode("3000");
Transaction tx = session.beginTransaction();
address.setUser(user);
user.setBillingAddress(address);
tx.commit();
The USER table now defines two foreign keys referencing the primary key of the
Our advice is to avoid defining more than one one-to-one association between
For a primary key association, both ends of the association are mapped using the
<one-to-one> declaration.
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
...
<one-to-one name="user"
class="User"
constrained="true"/>
</class>
Two tables related by a primary key association share the same primary key values.
The primary key of one table is also a foreign key of the other.
The <param> named property of the foreign generator allows us to name a one-to-one
association of the Address class—in this case, the user association. The foreign
generator inspects the associated object (the User) and uses its identifier as the
table, the link table or association table. In this case, the link table has two columns:
<set name="items"
table="CATEGORY_ITEM"
lazy="true"
cascade="save-update">
<key column="CATEGORY_ID"/>
</set>
<idbag name="items"
table="CATEGORY_ITEM”
lazy="true"
cascade="save-update">
<generator class="sequence"/>
</collection-id>
<key column="CATEGORY_ID"/>
</idbag>
<list name="items"
table="CATEGORY_ITEM”
lazy="true"
cascade="save-update">
<key column="CATEGORY_ID"/>
<index column="DISPLAY_POSITION"/>
</list>
of the link table is represented by two collection elements, one element at each
<set name="items"
table="CATEGORY_ITEM"
lazy="true"
cascade="save-update">
<key column="CATEGORY_ID"/>
</set>
<idbag name="items"
table="CATEGORY_ITEM”
lazy="true"
cascade="save-update">
<generator class="sequence"/>
</collection-id>
<key column="CATEGORY_ID"/>
<many-to-many class="Item" column="ITEM_ID"/>
</idbag>
<list name="items"
table="CATEGORY_ITEM”
lazy="true"
cascade="save-update">
<key column="CATEGORY_ID"/>
<index column="DISPLAY_POSITION"/>
</list>
of the link table is represented by two collection elements, one element at each
When you map a bidirectional many-to-many association, you must declare one
end of the association using inverse="true" to define which side’s state is used to
... <
set name="items"
table="CATEGORY_ITEM"
lazy="true"
cascade="save-update">
<key column="CATEGORY_ID"/>
</set>
class>
...
<set name="categories"
table="CATEGORY_ITEM"
lazy="true"
inverse="true"
cascade="save-update">
<key column="ITEM_ID"/>
</set>
</class>
Note the use of inverse="true". Once again, this setting tells Hibernate to ignore
changes made to the categories collection and use the other end of the association
Indexed collections (lists and maps) can’t be used, since Hibernate won’t
. ...
<key column="CATEGORY_ID"/>
<composite-element class="CategorizedItem">
<parent name="category"/>
<many-to-one name="item"
class="Item"
column="ITEM_ID"
not-null="true"/>
</composite-element>
</set>
<key column="CATEGORY_ID"/>
<composite-element class="CategorizedItem">
<parent name="category"/>
<many-to-one name="item"
class="Item"
column="ITEM_ID"
not-null="true"/>
<many-to-one name="user"
class="User"
column="USER_ID"
not-null="true"/>
</composite-element>
</set>
<many-to-one name="billingDetails"
class="BillingDetails"
column="BILLING_DETAILS_ID"
cascade="save-update"/>
naturally polymorphic.
Transaction tx = session.beginTransaction();
user.getBillingDetails().pay(paymentAmount);
tx.commit();
session.close();
BillingDetails bd = user.getBillingDetails();
In this code, the typecast fails because bd is a proxy instance. When a method is
fetched lazily.
BillingDetails bd = user.getBillingDetails();
expiryDate = cc.getExpiryDate();
Note that you can avoid these issues by avoiding lazy fetching, as in the following
.setFetchMode("billingDetails", FetchMode.EAGER)
.uniqueResult();
expiryDate = cc.getExpiryDate();
<many-to-one name="user"
class="User"
column="USER_ID"/>
<set name="billingDetails"
lazy="true"
cascade="save-update"
inverse="true">
<key column="USER_ID"/>
<one-to-many class="BillingDetails"/>
</set>
cc.setType(ccType);
cc.setExpiryDate(ccExpiryDate);
Transaction tx = session.beginTransaction();
user.addBillingDetails(cc);
tx.commit();
session.close();
Transaction tx = session.beginTransaction();
while ( iter.hasNext() ) {
bd.pay(ccPaymentAmount);
tx.commit();
session.close();
explicitly in the Hibernate mapping document, and that the inheritance mapping
to the table of the abstract superclass. There is no table for the superclass with this
this association:
<any name="billingDetails"
meta-type="string"
id-type="long"
cascade="save-update">
<meta-value value="BANK_ACCOUNT"class="BankAccount"/>
<column name="BILLING_DETAILS_TYPE"/>
<column name="BILLING_DETAILS_ID"/>
</any>
column; the id-type attribute specifies the type of the BILLING_DETAILS_ID column
(CreditCard and BankAccount must have the same identifier type). Note that
the order of the columns is important: first the type, then the identifier.
The <meta-value> elements tell Hibernate how to interpret the value of the
the Hibernate query facilities don’t support this kind of association mapping,
Queries are the most interesting part of writing good data access code. A complex
query may require a long time to get right, and its impact on the performance of
Next is the Criteria API for query by criteria (QBC) and query by example (QBE)):
session.createCriteria(Category.class)
session.createSQLQuery(
"c",
Category.class);
EXECUTING QUERIES
The Query and Criteria interfaces both define several methods for controlling
execution of a query
underlying database:
User.class
);
The Criteria instance may be used in the same way as a Query object—
Query query =
query.setFirstResult(0);
query.setMaxResults(10);
The call to setMaxResults(10) limits the query result set to the first 10 objects
crit.setFirstResult(40);
crit.setMaxResults(20);
List results =
.setFirstResult(0)
.setMaxResults(10)
.list();
List results =
session.createCriteria(User.class)
.addOrder( Order.asc("name") )
.setFirstResult(40)
.setMaxResults(20)
.list();
The list() method executes the query and returns the results as a list:
With some queries, we know the result will be only a single instance—
uniqueResult() method
Bid maxBid =
(Bid) session.createQuery("from Bid b order by b.amount desc")
.setMaxResults(1)
.uniqueResult();
.uniqueResult();
The Query and Session interfaces also provide the iterate() method, which
returns the same result as list() (or find()) but uses a different strategy for
shortcut methods for simple queries. Instead of creating a Query, you can
Query.list(); one isn’t faster than the other. The same is true for iterate():
BINDING PARAMETERS
String queryString =
String queryString =
.setString("searchString", searchString)
.list();
String queryString = "from Item item "
.setString("searchString", searchString)
.setDate("minDate", minDate)
.list()
.setString(0, searchString)
.setDate(1, minDate)
.list();
entity:
.list();
Query q =
q.setParameter( "amount",
givenAmount,
Hibernate.custom(MonetaryAmountUserType.class) );
session.createQuery(queryString)
.list();
session.createQuery(queryString)
.setParameter("seller", seller)
.setParameter("desc", description)
.list();
nicely for String, Integer, and Boolean parameters, for example, but not so well
for Date, where the Hibernate type might be timestamp, date, or time.
If we had a JavaBean with seller and description properties, we could use the
setProperties() method to bind the query parameters.
item.setSeller(seller);
item.setDescription(description);
session.createQuery(queryString).setProperties(item).list();
metadata, a technique that is called named queries. This allows you to store all queries
related to a particular persistent class (or a set of classes) encapsulated with the
session.getNamedQuery("findItemsByDescription")
.setString("description", description)
.list();
<query name="findItemsByDescription"><![CDATA[
]]></query>
<sql-query name="findItemsByDescription"><![CDATA[
select {i.*} from ITEM {i} where DESCRIPTION like :description
]]>
</sql-query>
from Bid
session.createCriteria(Bid.class);
USING ALIASES
...
POLYMORPHIC QUERIES
This query returns objects of the type BillingDetails, which is an abstract class.
session.createCriteria(BillingDetails.class).list();
RESTRICTION
crit.add(emailEq);
.uniqueResult();
.uniqueResult();
from USER U
COMPARISON OPERATORS
.add( Expression.between("amount",
new BigDecimal(1),
new BigDecimal(10))
).list();
session.createCriteria(Bid.class)
.list();
session.createCriteria(User.class)
.list();
session.createCriteria(User.class)
.add( Expression.isNull("email") )
.list();
session.createCriteria(User.class)
.add( Expression.isNotNull("email") )
.list();
STRING MATCHING
The like operator allows wildcard searches, where the wildcard symbols are % and
_, just as in SQL:
from User u where u.firstname not like "%Foo B%"
This expression restricts the result to users with a first name starting with a capital
G.
session.createCriteria(User.class)
.list();
session.createCriteria(User.class)
.list();
session.createCriteria(User.class)
.list();
LOGICAL OPERATORS
session.createCriteria(User.class)
.add( Expression.like("firstname", "G%") )
.add(
Expression.or(
Expression.and(
Expression.like("firstname", "G%"),
Expression.like("lastname", "K%")
),
Expression.in("email", emails)
);
.add( Expression.disjunction()
.add( Expression.conjunction()
);
.addOrder( Order.asc("lastname") )
.addOrder( Order.asc("firstname") )
.list();
JOINING ASSOCIATIONS
session.createCriteria(Item.class)
.setFetchMode("bids", FetchMode.EAGER)
.list();
from ITEM I
session.createCriteria(Bid.class)
.setFetchMode("item", FetchMode.EAGER)
.setFetchMode("bidder", FetchMode.EAGER)
.list();
from BID B
FetchMode.LAZY)
Session.load()
from ITEM I
while ( pairs.hasNext() ) {
select item
Instead of a List of Items, this query returns a List of Object[] arrays. At index 0
is the Item, and at index 1 is the Bid. A particular Item may appear multiple times,
select item
from ITEM I
while ( items.hasNext() ) {
itemCriteria.add( Expression.like("description",
"gc",
MatchMode.ANYWHERE) );
List results =
session.createCriteria(Item.class)
.createCriteria("bids")
.list();
List results =
session.createCriteria(Item.class)
.createAlias("bids", "bid")
.list();
Iterator items =
session.createCriteria(Item.class)
.createAlias("bids", "bid")
.list().iterator();
while ( items.hasNext() ) {
// Do something
Iterator itemBidMaps =
session.createCriteria(Item.class)
.createAlias("bids", "bid")
.returnMaps()
.list().iterator();
while ( itemBidMaps.hasNext() ) {
// Do something
}
USING IMPLICIT JOINS
session.createCriteria(User.class)
select ...
from BID B
Iterator i = session.createQuery(
.list().iterator();
while ( i.hasNext() ) {
Query q =
q.setLong("id", userId);
Iterator i = session.createQuery(
.list()
.iterator();
while ( i.hasNext() ) {
// Do something
Integer count =
.uniqueResult();
group by u.lastname
from USER U
group by U.LAST_NAME
group by bid.item.id
group by bid.item.id
group by user.lastname
group by item.id
group by bid.item.id
group by user.lastname
DYNAMIC QUERIES
String lastname)
throws HibernateException {
if (firstname != null) {
crit.add( Expression.ilike("firstname",
firstname,
MatchMode.ANYWHERE) );
if (lastname != null) {
crit.add( Expression.ilike("lastname",
lastname,
MatchMode.ANYWHERE) );
crit.addOrder( Order.asc("username") );
return crit.list();
}
Example exampleUser =
Example.create(u).ignoreCase().enableLike(MatchMode.ANYWHERE);
return getSession().createCriteria(User.class)
.add(exampleUser)
.list();
Example exampleUser =
Example.create(u).ignoreCase().enableLike(MatchMode.ANYWHERE);
return getSession().createCriteria(User.class)
.add( exampleUser )
.createCriteria("items")
.add( Expression.isNull("successfulBid") )
.list();
COLLECTION FILTERS
List results =
.setEntity("item", item)
.list();
String query = "select bid from Item item join item.bids bid "
.setEntity("item", item)
.list();
List results =
session.createFilter( item.getBids(),
"select this.bidder" )
.list();
item.getBids(),
"select elements(this.bidder.bids)"
).list();
List results =
session.createFilter( user.getBids(),
.setTimestamp("oneWeekAgo", oneWeekAgo)
.list();
SUBQUERIES
)
from Bid bid where bid.amount + 1 >= (
from Item item where 100 > all ( select b.amount from item.bids b )
from Item item where 100 < any ( select b.amount from item.bids b )
from Item item where 100 = some ( select b.amount from item.bids b )
.setEntity("item", item)
.list();
.setEntity("item", item)
.list();
while (items.hasNext()) {
if ( bid.getAmount().compareTo(maxAmount) == 1 )
maxAmount = bid.getAmount();
.setEntity("
Occasionally
So, we have established a general solution to the n+1 selects problem. Rather
than retrieving just the top-level objects in the initial query and then fetching
needed associations as the application navigates the object graph, we follow a twostep
process:
1 Fetch all needed data in the initial query by specifying exactly which associations
for ( ; items.hasNext(); ) {
if ( bid.getAmount().compareTo(maxAmount) == 1 )
maxAmount = bid.getAmount();
Query categoryByName =
categoryByName.setString("name", categoryNamePattern);
Query categoryByName =
categoryByName.setString("name", categoryNamePattern);
hibernate.cache.use_query_cache true
Query categoryByName =
categoryByName.setString("name", categoryName);
categoryByName.setCacheable(true);
Query userByName =
userByName.setString("uname", username);
userByName.setCacheable(true);
userByName.setCacheRegion("UserQueries");
static {
try {
sessionFactory = cfg.configure().buildSessionFactory();
ex.printStackTrace(System.out);
}
}
return sessionFactory.openSession();
try {
Transaction tx = session.beginTransaction();
try {
LockMode.UPGRADE);
Query q =
session.createQuery("select max(b.amount)" +
q.setEntity("item", item);
if (maxBidAmount.compareTo(bidAmount) > 0) {
item.addBid(newBid);
tx.commit();
throw ex;
} finally {
session.close();
request.
The thread-local session pattern allows you to have a single Hibernate session per
request, spanning the view and potentially multiple action executes(). Java provides
new ThreadLocal();
new ThreadLocal();
static {
// Initialize SessionFactory...
try {
if (s == null) {
s = sessionFactory.openSession();
threadSession.set(s);
return s;
try {
threadSession.set(null);
s.close();
try {
if (tx == null) {
tx = getSession().beginTransaction();
threadTransaction.set(tx);
try {
&& !tx.wasRolledBack() )
tx.commit();
threadTransaction.set(null);
rollbackTransaction();
try {
threadTransaction.set(null);
&& !tx.wasRolledBack() ) {
tx.rollback();
} finally {
closeSession();
}
It provides threadlocal
ServletResponse response,
FilterChain chain)
try {
chain.doFilter(request, response);
HibernateUtil.commitTransaction();
} finally {
HibernateUtil.closeSession();
try {
HibernateUtil.beginTransaction();
throws BusinessException {
this.addBid(newBid);
return newBid;
try {
HibernateUtil.beginTransaction();
Query q =
session.createQuery("select max(b.amount)" +
q.setEntity("item", item);
if (maxBidAmount.compareTo(bidAmount) > 0) {
// Place Bid
public ItemDAO() {
HibernateUtil.beginTransaction();
try {
return item;
try {
Query q = session.createQuery(query);
q.setLong("itemId", itemId.longValue());
return maxBidAmount;
public UserDAO() {
HibernateUtil.beginTransaction();
try {
return user;
try {
if (itemDAO.getMaxBidAmount(itemId).compareTo(bidAmount) > 0)
Bid newBid =
item.placeBid(userDAO.getUserById(userId), bidAmount);
approach, where the view was allowed to pull data from the domain model objects
as needed. Instead, the business (EJB) tier must accept responsibility for fetching
all data that will be needed subsequently for rendering the view
static {
try {
new Configuration().configure().buildSessionFactory();
ex.printStackTrace(System.out);
try {
sessions = (SessionFactory)ctx.lookup(jndiName);
return sessions;
implements javax.ejb.SessionBean {
try {
command.execute();
HibernateUtil.rollbackTransaction();
throw ex;
return command;
}
public void execute() {
BidForItemCommand bidForItem =
try {
CommandHandler handler =
(CommandHandler) ctx.lookup(jndiName);
bidForItem =
(BidForItemCommand) handler.executeCommand(bidForItem);
// bidForItem.getNewBid();
// ex.getCause();
implements Command {
Long itemId,
BigDecimal bidAmount) {
this.userId = userId;
this.itemId = itemId;
this.bidAmount = bidAmount;
return newBid;
try {
BigDecimal currentMaxAmount =
itemDAO.getMaxBidAmount(itemId);
BigDecimal currentMinAmount =
itemDAO.getMinBidAmount(itemId);
currentMaxAmount, currentMinAmount);
HibernateUtil.commitTransaction();
} finally {
HibernateUtil.closeSession();
}
APPLICATION TRANSACTIONS
that uses Hibernate: using a long session, using detached objects, and doing it the hard
way.
instances between each request. The justification for this approach is that, since
the database transaction is ended, the persistent instances are no longer guaranteed
You call session.lock() to reassociate items with a new hybernate session and ensure that any subsequent change
to the state of the item is propagated to
Alternatively, we could use update(). For our example, the only real difference is
that update() may be called after the state of the item has been modified
The disconnect() method releases the session’s JDBC connection without closing
the session; the reconnect() method acquires a new connection for the same
session. These methods let you have a session that spans multiple requests (a long
ServletResponse response,
FilterChain chain)
HttpSession userSession =
((HttpServletRequest) request).getSession();
Session hibernateSession =
(Session) userSession.getAttribute("HibernateSession");
if (hibernateSession != null)
HibernateUtil.reconnect(hibernateSession);
try {
chain.doFilter(request, response);
HibernateUtil.commitTransaction();
} finally {
hibernateSession = HibernateUtil.disconnectSession();
Before running the filter chain, we check whether the user session contains an
existing Hibernate Session and, if found, reconnect() it and associate it with the
current thread. The disconnect and reconnect operations detach the Hibernate session
the beginning of an application transaction. This method must close the existing
session and open a new one. Together with the disconnect() and reconnect()
throws InfrastructureException {
try {
session.reconnect();
threadSession.set(session);
throws InfrastructureException {
threadSession.set(null);
session.disconnect();
return session;
closeSession();
transaction, just before the item for approval is shown to the administrator (before
HibernateUtil.newApplicationTx();
viewItem(itemId);
return ItemDAO.getItemById(itemId);
flush it at the end of the application transaction. All changes are held in memory
A Hibernate Session isn’t threadsafe, and the servlet engine allows multiple requests from
the same user to be processed concurrently. So, it’s possible that two concurrent
requests could obtain the same Hibernate Session from the HttpSession if, for
example, the user clicked a submit button twice. This would result in unpredictable
behavior.
with a new session per database transaction. In particular, this is the method of
choice for an application where business logic and data access execute in the EJB
tier but where the domain model is also used in the web tier, avoiding the need for
tedious DTOs.
Instead, we’d use the long session approach in the case of a servlet-only application.
and make no changes to the existing data model—a new application usually
database schema.
<generator class="assigned"/>
</id>
user.setFirstname("John");
user.setLastname("Doe");
session.flush();
<composite-id>
<key-property name="username"
column="USERNAME"/>
<key-property name="organizationId"
column="ORGANIZATION_ID"/>
</composite-id>
<version name="version"
column="VERSION"
unsaved-value="0"/>
...
</class>
this.username = username;
this.organizationId = organizationId;
// Getters...
if (!organizationId.equals(userId.getOrganizationId()))
return false;
if (!username.equals(userId.getUsername()))
return false;
return true;
return username.hashCode();
<key-property name="userName"
column="USERNAME"/>
<key-property name="organizationId"
column="ORGANIZATION_ID"/>
</composite-id>
<version name="version"
column="VERSION"
unsaved-value="0"/>
...
</class>
Now, suppose the ORGANIZATION_ID was a foreign key to the ORGANIZATION table,
and that we wished to represent this association in our Java model. Our recommended
<key-property name="userName"
column="USERNAME"/>
<key-property name="organizationId"
column="ORGANIZATION_ID"/>
</composite-id>
<version name="version"
column="VERSION"
unsaved-value="0"/>
<many-to-one name="organization"
class="Organization"
column="ORGANIZATION_ID"
insert="false" update="false"/>
...
</class>
<key-property name="userName"
column="USERNAME"/>
<key-many-to-one name="organization"
class="Organization"
column="ORGANIZATION_ID"/>
</composite-id>
<version name="version"
column="VERSION"
unsaved-value="0"/>
...
</class>
to a composite foreign key. We can use the following association mapping for Item:
<column name="USERNAME"/>
<column name="ORGANIZATION_ID"/>
</many-to-one>
Any collection owned by the User class will also have a composite foreign key
<key>
<column name="USERNAME"/>
<column name="ORGANIZATION_ID"/>
</key>
<one-to-many class="Item"/>
</set>
return true;
name.getInitial(),
name.getLastname());
throws HibernateException {
String[] names,
Object owner)
String dbName =
Name realName =
new Name( tokens.nextToken(),
String.valueOf(tokens.nextToken().charAt(0)),
tokens.nextToken() );
return realName;
Object value,
int index)
null :
name.getFirstname()
we urge you to
table changes and exporting/importing data solves the problem, one day of work
AUDIT LOGGING
An audit log is a database table that contains information about changes made to
other data, specifically about the event that results in the change.
2 Define the information that should be logged: user, date, time, type of modification,
and so on.
...
AuditLogRecord() {}
Long entityId,
Class entityClass,
Long userId) {
this.message = message;
this.entityId = entityId;
this.entityClass = entityClass;
this.userId = userId;
}
}
<hibernate-mapping>
<class name="org.hibernate.auction.persistence.audit.AuditLogRecord"
table="AUDIT_LOG"
mutable="false">
<generator class="native"/>
</id>
not-null="true" access="field"/>
not-null="true" access="field"/>
not-null="true" access="field"/>
not-null="true" access="field"/>
type="java.util.Date" not-null="true"
access="field"/>
</class>
</hibernate-mapping>
(or any other similar event listener). This extension is known as a Hibernate
Interceptor.
this.session=session;
this.userId=userId;
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException {
inserts.add(entity);
return false;
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types)
throws CallbackException {
updates.add(entity);
return false;
try {
AuditLog.logEvent("create",
entity,
userId,
session.connection());
AuditLog.logEvent("update",
entity,
userId,
session.connection());
} finally {
inserts.clear();
updates.clear();
...
is called whenever Hibernate detects a dirty object. The audit logging is done in
the postFlush() method, which Hibernate calls after executing the synchronization
SQL. We use the static call AuditLog.logEvent()
Session session =
HibernateUtil.getSessionFactory().openSession(interceptor);
Transaction tx = session.beginTransaction();
interceptor.setSession(session);
interceptor.setUserId( currentUser.getId() );
session.close();
It’s illegal to invoke the original Hibernate Session from an Interceptor callback.
avoids this issue is to open a new Session for the sole purpose of saving a single
AuditLogRecord object.
String message,
Auditable entity,
Long userId,
Connection connection)
throws CallbackException {
Session tempSession =
HibernateUtil.getSessionFactory().openSession(connection);
try {
AuditLogRecord record =
new AuditLogRecord(message,
entity.getId(),
entity.getClass(),
userId );
tempSession.save(record);
tempSession.flush();
} finally {
try {
tempSession.close();
OOLS
TOP DOWN
BOTTOM UP
existing database
ROUND TRIPPING
Existing database schema,
hbm2ddl
<generator class="uuid.hex"/>
</id>
<column name="NAME"
not-null="true"
length="255"
index="IDX_ITEMNAME"/>
</property>
<property name="description"
type="string"
column="DESCRIPTION"
length="4000"/>
<property name="initialPrice"
type="customtype.MonetaryAmount">
<column name="INITIAL_PRICE_CURRENCY"/>
</property>
<key
<column="ITEM_ID" sql-type="char(32)"/>
</key>
<many-to-many class="Category">
<column="CATEGORY_ID" sql-type="char(32)/>
</many-to-many>
</set>
...
</class>
CREATING A SCHEMA
options mapping_files
schemaExport.create(false, true);
Hibernate comes bundled with a tool for schema evolution, SchemaUpdate, which
and constraints. It uses the JDBC metadata and creates new tables and constraints
schemaUpdate.execute(false, true);
tool is also known as CodeGenerator, and it’s available in the optional HibernateExtensions
distribution.
development approach
- POJO source generation from mapping files that have also been automatically
By default, hbm2java produces a simple POJO persistent class. The class implements
GENERATING FINDERS
<property name="username"
type="string">
<meta attribute="use-in-tostring">true</meta>
<meta attribute="finder">findByUsername</meta>
</property>
username, Hibernate.STRING);
return finds;
options mapping_files
MIDDLEGEN
Middlegen isn’t limited to Hibernate metadata; it can also generate EJB entity
bean code or Struts actions and JSP code through its plugins architecture.
<middlegen appname="CaveatEmptor"
prefsdir="${basedir}" gui="true"
databaseurl="jdbc:oracle:thin:@localhost:1521:orac"
driver="oracle.jdbc.driver.OracleDriver"
username="test"
password="test"
schema="auction">
<hibernate destination="generated/src"
package="org.hibernate.auction.model"/>
</middlegen>
<hibernate destination="generated/src/"
package="org.hibernate.auction.model"/>
<many2many>
<tablea name="CATEGORY"/>
<tableb name="ITEM"/>
</many2many>
XDOCLET
XDoclet is the tool that reads these meta-attributes and generates Hibernate mapping
files. XDoclet isn’t limited to Hibernate; it can generate all kinds of XMLbased
/**
* @hibernate.class
* table="USERS"
*/
public class User implements Serializable {
...
<hibernate-mapping>
<class
name="User"
table="USERS">
/**
* @hibernate.id
* column="USER_ID"
* unsaved-value="null"
* generator-class="native"
*/
return id;
/**
* @hibernate.property
* column="USERNAME"
* length="16"
* not-null="true"
* unique="true"
* update="false"
*/
return username;
}
We have one more value-typed property in User, the Address component:
/**
* @hibernate.component
*/
return address;
/**
* @hibernate.set
* inverse="true"
* lazy="true"
* cascade="save-update"
* @hibernate.collection-key
* column="SELLER_ID"
* @hibernate.collection-one-to-many
* class="Item"
*/
return items;
the seller:
/**
* @hibernate.many-to-one
* column="SELLER_ID"
* cascade="none"
* not-null="true"
*/
return seller;
<taskdef name="hibernatedoclet"
classname="xdoclet.modules.hibernate.HibernateDocletTask"
classpathref="class.path"/>
<taskdef name="hibernatedoclet"
classname="xdoclet.modules.hibernate.HibernateDocletTask"
classpathref="class.path"/>
<target name="xdoclet">
<hibernatedoclet
destdir="mappings/"
excludedtags="@version,@author,@todo"
force="true"
mergedir="merge/">
<fileset dir="src">
<include name="**/org/hibernate/auction/*.java"/>
</fileset>
<hibernate version="2.0"/>
</hibernatedoclet>
</target>
This blog is a companion site to http://www.mydeveloperconnection.com/ . You can find lots of programming and
technology articles and tips in mydeveloperconnection web site.
While using hbm2ddl for schema creation and update, if you want it to set a default value for the new column, use
"default" property in hbm.
Example:
</property>
Although hibernate documentation also mention to have insert="false" attribute, but it seems to be working even
otherwise. The resultant effect would be same as using default in alter/create table SQL statements for schema
creation/update.
When you have lazy initialization turned on (default) in hibernate, you have to invoke seperate getter/find quary to
retrieve child collections.
Sometimes you want to bypass lazy initialization for instance during schema migration.
You can use Hibernate HQL semantics of "fetch" to retrieve child collection in one query.
Example:
from MyEntity as me inner join fetch me.childEntityCollection
The above query gets MyEntity with child childEntities already populated instead of proxy holders.
For complete list of hibernate best practices visit this blog home: http://hibernatebp.blogspot.com/
Unitils is a java open source which uses standard unite testing framework such as JUnit, DBUnit and EasyMock.
Unitils contains a very simple but powerful mapping test. This test checks whether the mapping of all Hibernate
mapped objects is consistent with the database. To activate it, just add following test to your test suite:
@SpringApplicationContext({"classpath:services-config.xml", "classpath:test-ds-config.xml"})
HibernateUnitils.assertMappingWithDatabaseConsistent(); }}
Suppose that the column PERSON.FIRSTNAME is missing in the test database. This will make the test fail with a
message indicating that this column should be added:
AssertionFailedError: Found mismatches between Java objects and database tables. Applying following DDL
statements to the database should resolve the problem: alter table PERSON add column firstName varchar(255);
ORMUnit from the author of "POJOs in Action" also comes very handy for testing hibernate based applications.It
could be now downloaded from http://code.google.com/p/ormunit/
A basic Hibernate client/server application may be designed with server-side units of work that span a single client
request.When a request from the application user requires data access, a new unit of work is started. The unit of
work endswhen processing is complete and the response for the user is ready. This is session-per-request strategy.
In a scenario like web applications, you don’t usually maintain a database transaction across a user interaction.
Users take a long time to think about modifications. You can handle this scenario either by extending the
persistence context or using detached objects. Hibernate objects are automayically detached when session is
closed. You have to just call update to reattach it with session. This strategy is called session-per-request-with-
detached objects.
You can also extend a persistence context to span the whole transaction unit. That is session per application
transaction which spans across multiple requests. Also known as sesseion per conversation.
At the end of a unit of work, all the modifications you made, have to be synchronized with database through SQL
DML statements. This process is called flushing of the persistence context. If a single property of an object is
changed twice in the same persistence context, Hibernate needs to execute only one SQL UPDATE.Hibernate
flushes occur at the following times:
You can control this behavior by explicitly setting the Hibernate FlushMode via call to session.setFlushMode(). The
default flush mode is FlushMode.AUTO and enables the behavior described previously. If you chose
FlushMode.COMMIT, the persistence context isn’t flushed before query execution. It is flushed only when you call
Transaction.commit() or Session.flush() manually. Repeated flushing of the persistence context is often a source
for performance issues, because all dirty objects in the persistence context have to be detected atflush-time. A
common cause is a particular unit-of-work pattern that repeats aquery and update sequence many times. Every
update leads to a flush and a dirty check of all persistent objects, before each query. A Flush-Mode.COMMIT may
be appropriate in this situation. The performance of the flush setting also depends on the size of the persistence
context i.e the number of persistent objects it manages.
Hibernate supports query cache which stores the primary keys of the objects found by a query. When it executes a
query hibernate looks into query cache for the results before accessing the database. A query cache is useful for
read only data because hibernate flushes all cached queries that involves a modified table.
In order to decide whether to leave the default lazy loading or go for eager loading, you should analyze
relationships that are traversed in each request. If the application always traverses a relationship, it should be
early loaded. By default hibernate lazily loads objects and collection and uses seperate SQL SELECT statement for
each object or collection. In eager loading all the objects would be fetched in single SELECT.
Sometime different requests require different objects to be eagerly loaded. A fetch join identifies relationship to
eagerly load. HQL with fetch join ignores lazy loading settings specified in mapping.
Example:
from Order orderleft outer join fetch order.catalogleft outer join fetch order.lineitems as lineitemsleft outer join
fetch lineitem.product where order.id = ?
There are several limitations to fetch join such as duplicate data and ability to fetch only single collection. Also it is
too verbose.
In hibernate Session is your 1st level cache. Hibernate has a pluggable 2nd level caching architecture and there are
several caching frameworks such as EHCache that supports process level cache. In hibernate caching is configured
on per class or per collection basis. If you specify read-only, objects that are never modified by application are
cached. If you specify read/write, objects that are modiefied by application are cached.
If you use the identifier as part of your equals() and hashCode() implementation, add the entity to a Set before
you save it.
I personally do not like java annotations but if you want to use it for out of box validation, here is a decent
tutorial:http://www-128.ibm.com/developerworks/java/library/j-hibval.html
Choose the right inheritence mapping strategy which suits your needs. Debate with domain architect and comeup
with right OO design. Sometimes a good OO design might not be necessarily good for performance. You can refer
to: http://www-128.ibm.com/developerworks/java/library/j-hibernate/
For complete list of hibernate best practices visit this blog home: http://hibernatebp.blogspot.com/
You know it but just a reminder that HQL queries refer to object properties not database column's.
Realize mapping with respect to the database table model you are expecting. Whether you are using middlegen to
start your hibernate project from existing schema or starting from scratch, you should visualize the outcome in
terms of traditional db model and SQLs.It takes the surprise factor out and makes the design more predictable
specially when you want to choose between association/composition or inheritance/composition.
Properties or attributes of POJO class need not be public. Hibernate's fundamental persistence architecture is based
on reflection. Hibernate only enforces for having accessor getters and setters methods. This is more of a good OO
design practice to keep class attributes private.
Place hbm.xml file in same package as your source. It will be useful while packaging as jar for web applications.
Creating session factory is a slow operation. You can take help from spring to maintain single session factory
throughout your application per database. Session Factory is thread safe anyway. Please note that session object is
not thread safe and it should be retrieved from session factory as and when required. Hibernate defines two states
for any mapped object: transient and persistent. Transient object is like disassociated object and mapped is
associated with a particular session.
Implement object versioning if required to resolve conflict. Most of the time you work with offline set of objects and
persist them when required. It is advised to implement some sort of high level object versioning mechanism.
Hibernate does not lock objects in memory. Your application can expect the behavior as defined by the isolation
level of your database transactions. Hibernate provides automatic versioning and most of the cases it is sufficient.
Many business processes require a whole series of interactions with the user interleaved with database accesses.
Hibernate can automatically detect if a concurrent modification occured during user think time. It checks at the end
of the conversation. Hibernate checks instance versions during flush, throwing an exception if conflicting updates
occured. If you set optimistic-lock="dirty" when mapping , Hibernate will only compare dirty fields during flush.
Use Named queries and paremeters: Named queries and paremeters makes program more readable. Named
parameters are identified by ":". Query interface has type safe methods like setString, setTime to set values.
<hibernate-mapping">.........................
<query name="com.mydeveloperconnection.hibernateBP">
For complete list of hibernate best practices visit this blog home: http://hibernatebp.blogspot.com/
Avoid loading all objects to find count: This is a classic case, where we want total count of entity in database. Avoid
loading all objects and iterating through them to find count. Here is a simple way:
} );
For complete list of hibernate best practices visit this blog home: http://hibernatebp.blogspot.com/
Hibernate implements Java Persistence and supports all the standardized mappings,
queries, and APIs. Before we start with hibernate best practices, lets see who needs hibernate.
Application supporting various database and want to focus of their business logic instead of basic persistence
mechanism.
Application which already have to data store and want to remove clutter of SQLs all over the code to better
organized and maintained piece of software.
Applications driven by model such as UML. Declarative mappings in the form of XML is one of the reason for
hibernate's popularity. There are several MDA tools such AndroMDA, middlegen which facilitates generating
hibernate mapping file automatically and java code from it.
Many more..
However hibernate is not meant for die hard fans of complex SQLs and for application where large portion of
business logic reside in their mile long stored procedures. Hibernate is also not yet designed for large scale data
warehousing or data mart applications which uses underlying database server's additional capabilities for
performance and scalability. A dashboard application working on top of data warehouse can use hibernate
efficiently.