Jboss Enterprise Web Platform 5 Hibernate Entity Manager Reference Guide
Jboss Enterprise Web Platform 5 Hibernate Entity Manager Reference Guide
Web Platform 5
Hibernate Entity Manager
Reference Guide
for Use with JBoss Enterprise Web Platform 5
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons
Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available
at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this
document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert,
Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity
Logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States
and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other
countries.
The Hibernate Entity Manager Reference Guide for JBoss Enterprise Web Platform 5.0 and its patch
releases.
Introducing EJB3 Persistence v
1. Architecture 1
1.1. Definitions .................................................................................................................... 1
1.2. EJB container environment ........................................................................................... 1
1.2.1. Container-managed entity manager .................................................................... 1
1.2.2. Application-managed entity manager .................................................................. 2
1.2.3. Persistence context scope ................................................................................. 2
1.2.4. Persistence context propagation ......................................................................... 2
1.3. Java SE environments .................................................................................................. 3
iii
Hibernate Entity Manager Reference Guide
iv
Introducing EJB3 Persistence
The EJB3 specification recognizes the interest and the success of the transparent object/relational
mapping paradigm. The EJB3 specification standardizes the basic APIs and the metadata needed for
any object/relational persistence mechanism. Hibernate EntityManager implements the programming
interfaces and lifecycle rules as defined by the EJB3 persistence specification. Together with
Hibernate Annotations, this wrapper implements a complete (and standalone) EJB3 persistence
solution on top of the mature Hibernate core. You may use a combination of all three together,
annotations without EJB3 programming interfaces and lifecycle, or even pure native Hibernate,
depending on the business and technical needs of your project. You can at all times fall back to
Hibernate native APIs, or if required, even to native JDBC and SQL.
v
vi
Chapter 1.
Architecture
1.1. Definitions
EJB3 is part of the Java EE 5.0 platform. Persistence in EJB3 is available in EJB3 containers, as
well as for standalone J2SE applications that execute outside of a particular container. The following
programming interfaces and artifacts are available in both environments.
EntityManagerFactory
An entity manager factory provides entity manager instances, all instances are configured to
connect to the same database, to use the same default settings as defined by the particular
implementation, etc. You can prepare several entity manager factories to access several data
stores. This interface is similar to the SessionFactory in native Hibernate.
EntityManager
The EntityManager API is used to access a database in a particular unit of work. It is used to
create and remove persistent entity instances, to find entities by their primary key identity, and to
query over all entities. This interface is similar to the Session in Hibernate.
Persistence context
A persistence context is a set of entity instances in which for any persistent entity identity there is
a unique entity instance. Within the persistence context, the entity instances and their lifecycle is
managed by a particular entity manager. The scope of this context can either be the transaction, or
an extended unit of work.
Persistence unit
The set of entity types that can be managed by a given entity manager is defined by a persistence
unit. A persistence unit defines the set of all classes that are related or grouped by the application,
and which must be collocated in their mapping to a single data store.
1
Chapter 1. Architecture
The most common case is to bind the persistence context scope to the current transaction scope. This
is only doable when JTA transactions are used: the persistence context is associated with the JTA
transaction life cycle. When a entity manager is invoked, the persistence context is also opened, if
there is no persistence context associated with the current JTA transaction. Otherwise, the associated
persistence context is used. The persistence context ends when the JTA transaction completes. This
means that during the JTA transaction, an application will be able to work on managed entities of the
same persistence context. In other words, you don't have to pass the entity manager's persistence
context across your EJB method calls, but simply use dependency injection or lookup whenever you
need an entity manager.
You can also use an extended persistence context. This can be combined with stateful session beans,
if you use a container-managed entity manager: the persistence context is created when an entity
manager is retrieved from dependency injection or JNDI lookup, and is kept until the container closes
it after the completion of the Remove stateful session bean method. This is a perfect mechanism
for implementing a "long" unit of work pattern. For example, if you have to deal with multiple user
interaction cycles as a single unit of work (e.g. a wizard dialog that has to be fully completed), you
usually model this as a unit of work from the point of view of the application user, and implement
it using an extended persistence context. Please refer to the Hibernate reference manual or the
book Hibernate In Action for more information about this pattern. JBoss Seam is a framework that
link together JSF and EJB3 around the notion of conversation and unit of work. For an application-
managed entity manager the persistence context is created when the entity manager is created and
kept until the entity manager is closed. In an extended persistence context, all modification operations
(persist, merge, remove) executed outside a transaction are queued until the persistence context
is attached to a transaction. The transaction typically occurs at the user process end, allowing the
whole process to be commited or rollbacked. For application-managed entity manager only support
the extended persistence context.
2
Java SE environments
Important: persistence context are never shared between different JTA transactions or between
entity manager that do not came from the same entity manager factory. There are some noteworthy
exceptions for context propagation when using extended persistence contexts:
• If a stateless session bean, message-driven bean, or stateful session bean with a transaction-
scoped persistence context calls a stateful session bean with an extended persistence context in the
same JTA transaction, an IllegalStateException is thrown.
• If a stateful session bean with an extended persistence context calls a stateless session bean or a
stateful session bean with a transaction-scoped persistence context in the same JTA transaction,
the persistence context is propagated.
• If a stateful session bean with an extended persistence context calls a stateless or stateful session
bean in a different JTA transaction context, the persistence context is not propagated.
• If a stateful session bean with an extended persistence context instantiates another stateful session
bean with an extended persistence context, the extended persistence context is inherited by
the second stateful session bean. If the second stateful session bean is called with a different
transaction context than the first, an IllegalStateException is thrown.
• If a stateful session bean with an extended persistence context calls a stateful session bean with a
different extended persistence context in the same transaction, an IllegalStateException is thrown.
Extended context means that a persistence context is created when the entity manager is retrieved
(using EntityManagerFactory.createEntityManager(...) ) and closed when the entity
manager is closed. Many resource-local transaction share the same persistence context, in this case.
3
4
Chapter 2.
2.2.1. Packaging
The configuration for entity managers both inside an application server and in a standalone
application reside in a persistence archive. A persistence archive is a JAR file which must define a
persistence.xml file that resides in the META-INF folder. All properly annotated classes included
in the archive (ie having an @Entity annotation), all annotated packages and all Hibernate hbm.xml
files included in the archive will be added to the persistence unit configuration, so by default, your
persistence.xml will be quite minimalist:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/
persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="sample">
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/
persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="manager1" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/DefaultDS</jta-data-source>
<mapping-file>ormap.xml</mapping-file>
<jar-file>MyApp.jar</jar-file>
<class>org.acme.Employee</class>
<class>org.acme.Person</class>
<class>org.acme.Address</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>
5
Chapter 2. Setup and configuration
name
(attribute) Every entity manager must have a name.
transaction-type
(attribute) Transaction type used. Either JTA or RESOURCE_LOCAL (default to JTA in a JavaEE
environment and to RESOURCE_LOCAL in a JavaSE environment). When a jta-datasource is
used, the default is JTA, if non-jta-datasource is used, RESOURCE_LOCAL is used.
provider
The provider is a fully-qualified class name of the EJB Persistence provider. You do not have to
define it if you don't work with several EJB3 implementations. This is needed when you are using
multiple vendor implementations of EJB Persistence.
jta-data-source, non-jta-data-source
This is the JNDI name of where the javax.sql.DataSource is located. When running without a JNDI
available Datasource, you must specify JDBC connections with Hibernate specific properties (see
below).
mapping-file
The class element specifies a EJB3 compliant XML mapping file that you will map. The file has
to be in the classpath. As per the EJB3 specification, Hibernate EntityManager will try to load the
mapping file located in the jar file at META_INF/orm.xml. Of course any explicit mapping file will
be loaded too. As a matter of fact, you can provide any XML file in the mapping file element ie.
either hbm files or EJB3 deployment descriptor.
jar-file
The jar-file elements specifies a jar to analyse. All properly annotated classes, annotated
packages and all hbm.xml files part of this jar file will be added to the persistence unit
configuration. This element is mainly used in Java EE environment. Use of this one in Java SE
should be considered as non portable, in this case a absolute url is needed. You can alternatively
point to a directory (This is especially useful when in your test environment, the persistence.xml
file is not under the same root directory or jar than your domain model).
<jar-file>file:/home/turin/work/local/lab8/build/classes</jar-file>
exclude-unlisted-classes
Do not check the main jar file for annotated classes. Only explicit classes will be part of the
persistence unit.
class
The class element specifies a fully qualified class name that you will map. By default all properly
annotated classes and all hbm.xml files found inside the archive are added to the persistence
unit configuration. You can add some external entity through the class element though. As
an extension to the specification, you can add a package name in the <class> element (eg
<class>org.hibernate.eg</class>). Specifying a package in the <class> element will
include only the annotated classes.
properties
The properties element is used to specify vendor specific properties. This is where you will
define your Hibernate specific configurations. This is also where you will have to specify JDBC
connection information as well.
Be sure to define the grammar definition in the persistence element since the EJB3 specification
requires the schema validation. If the systemId ends with persistence_1_0.xsd, Hibernate
6
Bootstrapping
entityManager will use the version embedded in the hibernate-entitymanager.jar. No internet access
will be performed.
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/
persistence/persistence_1_0.xsd"
version="1.0">
2.2.2. Bootstrapping
The EJB3 specification defines a bootstrap procedure to access the EntityManagerFactory and
the EntityManager. The bootstrap class is javax.persistence.Persistence, e.g.
The first version is equivalent to the second with an empty map. The map version is a set of overrides
that will take precedence over any properties defined in your persistence.xml files. There are a couple
of EJB3 properties usable in the map:
Apart from Hibernate system-level settings, all the properties available in Hibernate can be set
in properties element of the persistence.xml file or as an override in the map you pass to
createEntityManagerFactory(). Please refer to the Hibernate reference documentation for a
complete listing. There are however a couple of properties available in the EJB3 provider only.
7
Chapter 2. Setup and configuration
Note that you can mix XML <class> declaration and hibernate.ejb.cfgfile usage in the
same configuration. Be aware of the potential clashes. The properties set in persistence.xml will
override the one in the defined hibernate.cfg.xml.
Note
8
Event listeners
<persistence>
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
<class>org.hibernate.ejb.test.Cat</class>
<class>org.hibernate.ejb.test.Distributor</class>
<class>org.hibernate.ejb.test.Item</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:."/>
<property name="hibernate.max_fetch_depth" value="3"/>
<!-- alternatively to <class> and <property> declarations, you can use a regular
hibernate.cfg.xml file -->
<!-- property name="hibernate.ejb.cfgfile" value="/org/hibernate/ejb/test/
hibernate.cfg.xml"/ -->
</properties>
</persistence-unit>
</persistence>
To ease the programmatic configuration, Hibernate Entity Manager provide a proprietary API. This
API is very similar to the Configuration API and share the same concepts: Ejb3Configuration.
Refer to the JavaDoc and the Hibernate reference guide for more detailed informations on how to use
it.
9
Chapter 2. Setup and configuration
Event Listeners
merge org.hibernate.ejb.event.EJB3MergeEventListener
create org.hibernate.ejb.event.EJB3PersistEventListener
create-onflush org.hibernate.ejb.event.EJB3PersistOnFlushEventListener
save org.hibernate.ejb.event.EJB3SaveEventListener
save-update org.hibernate.ejb.event.EJB3SaveOrUpdateEventListener
pre-insert org.hibernate.secure.JACCPreInsertEventListener,
org.hibernate.valitator.event.ValidateEventListener
pre-insert org.hibernate.secure.JACCPreUpdateEventListener,
org.hibernate.valitator.event.ValidateEventListener
pre-delete org.hibernate.secure.JACCPreDeleteEventListener
pre-load org.hibernate.secure.JACCPreLoadEventListener
post-delete org.hibernate.ejb.event.EJB3PostDeleteEventListener
post-insert org.hibernate.ejb.event.EJB3PostInsertEventListener
post-load org.hibernate.ejb.event.EJB3PostLoadEventListener
post-update org.hibernate.ejb.event.EJB3PostUpdateEventListener
Note that the JACC*EventListeners are removed if the security is not enabled.
You can configure the event listeners either through the properties (see Section 2.2, “Configuration
and bootstrapping”) or through the Ejb3Configuration.getEventListeners() API.
An entity manager factory is typically created at application initialization time and closed at application
end. It's creation is an expensive process. For those who are familiar with Hibernate, an entity
manager factory is very much like a session factory. Actually, an entity manager factory is a wrapper
on top of a session factory. Calls to the entityManagerFactory are thread safe.
Thanks to the EntityManagerFactory, you can retrieve an extended entity manager. The extended
entity manager keep the same persistence context for the lifetime of the entity manager: in other
words, the entities are still managed between two transactions (unless you call entityManager.clear()
in between). You can see an entity manager as a small wrapper on top of an Hibernate session.
10
Various
2.5. Various
Hibernate Entity Manager comes with Hibernate Validator configured out of the box. You don't have to
override any event yourself. If you do not use Hibernate Validator annotations in your domain model,
there will be no performance cost. For more information on Hibernate Validator, please refer to the
Hibernate Annotations reference guide.
11
12
Chapter 3.
• New (transient): an entity is new if it has just been instantiated using the new operator, and it is not
associated with a persistence context. It has no persistent representation in the database and no
identifier value has been assigned.
• Managed (persistent): a managed entity instance is an instance with a persistent identity that is
currently associated with a persistence context.
• Detached: the entity instance is an instance with a persistent identity that is no longer associated
with a persistence context, usually because the persistence context was closed or the instance was
evicted from the context.
• Removed: a removed entity instance is an instance with a persistent identity, associated with a
persistence context, but scheduled for removal from the database.
The EntityManager API allows you to change the state of an entity, or in other words, to load and
store objects. You will find persistence with EJB3 easier to understand if you think about object state
management, not managing of SQL statements.
If the DomesticCat entity type has a generated identifier, the value is associated to the instance
when persist() is called. If the identifier is not automatically generated, the application-assigned
(usually natural) key value has to be set on the instance before persist() is called.
In some cases, you don't really want to load the object state, but just having a reference to it (ie a
proxy). You can get this reference using the getReference() method. This is especially useful to
link a child to its parent without having to load the parent.
13
Chapter 3. Working with objects
child.SetName("Henry");
Parent parent = em.getReference(Parent.class, parentId); //no query to the DB
child.setParent(parent);
em.persist(child);
You can reload an entity instance and its collections at any time using the em.refresh() operation.
This is useful when database triggers are used to initialize some of the properties of the entity. Note
that only the entity instance and its collections are refreshed unless you specify REFRESH as a
cascade style of any associations:
em.persist(cat);
em.flush(); // force the SQL insert and triggers to run
em.refresh(cat); //re-read the state (after the trigger executes)
A query is usually executed by invoking getResultList(). This method loads the resulting
instances of the query completly into memory. Entity instances retrieved by a query are in persistent
state. The getSingleResult() method offers a shortcut if you know your query will only return a
single object.
3.4.1.1. Projection
An EJB3QL query queries can return tuples of objects if projection is used. Each result tuple is
returned as an object array:
Iterator<Cat[]> kittensAndMothers =
em.createQuery("select kitten, mother from Cat kitten join kitten.mother
mother").getResultList().iterator();
while (kittensAndMothers.hasNext()) {
Cat[] tuple = kittensAndMothers.next();
Cat kitten = tuple[0];
Cat mother = tuple[1];
}
....
}
14
Executing queries
while ( results.hasNext() ) {
Object[] row = results.next();
Color type = (Color) row[0];
Date oldest = (Date) row[1];
Integer count = (Integer) row[2];
.....
}
// Positional parameter
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = ?1");
q.setParameter(1, "Izi");
List cats = q.getResultList();
3.4.1.4. Pagination
If you need to specify bounds upon your result set (the maximum number of rows you want to retrieve
and/or the first row you want to retrieve), use the following methods:
Hibernate knows how to translate this limit query into the native SQL of your DBMS.
@javax.persistence.NamedQuery(name="eg.DomesticCat.by.name.and.minimum.weight",
query="select cat from eg.DomesticCat as cat where cat.name = ?1 and cat.weight > ?2")
15
Chapter 3. Working with objects
Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setParameter(1, name);
q.setParameter(2, minWeight);
List cats = q.getResultList();
Note that the actual program code is independent of the query language that is used, you may also
define native SQL queries in metadata, or use Hibernate's native facilities by placing them in XML
mapping files.
@SqlResultSetMapping(name="getItem", entities =
@EntityResult(entityClass=org.hibernate.ejb.test.Item.class, fields= {
@FieldResult(name="name", column="itemname"),
@FieldResult(name="descr", column="itemdescription")
})
)
Note
For more information about scalar support in named queries, please refers to the Hibernate
Annotations documentation
16
Modifying persistent objects
Hint Description
org.hibernate.cacheMode Override the cache mode for this query ( eg.
CacheMode.REFRESH )
org.hibernate.cacheRegion Cache region of this query ( eg. new
String("regionName") )
org.hibernate.readOnly Entities retrieved by this query will be loaded in a
read-only mode where Hibernate will never dirty-
check them or make changes persistent ( eg.
new Boolean(true) ), default to false
org.hibernate.flushMode Flush mode used for this query
org.hibernate.cacheMode Cache mode used for this query
The value object accept both the native type or its string equivalent (eg. CaheMode.REFRESH or
“REFRESH”). Please refer to the Hibernate reference documentation for more information.
Sometimes this programming model is inefficient since it would require both an SQL SELECT (to
load an object) and an SQL UPDATE (to persist its updated state) in the same session. Therefore
Hibernate offers an alternate approach, using detached instances.
The EJB3 specifications supports this development model by providing for persistence of modifications
made to detached instances using the EntityManager.merge() method:
17
Chapter 3. Working with objects
The merge() method merges modifications made to the detached instance into the corresponding
managed instance, if any, without consideration of the state of the persistence context. In other words,
the merged objects state overrides the persistent entity state in the persistence context, if one is
already present. The application should individually merge() detached instances reachable from the
given detached instance if and only if it wants their state also to be persistent. This can be cascaded
to associated entities and collections, using transitive persistence, see Section 3.10, “Transitive
persistence”.
The usage and semantics of merge() seems to be confusing for new users. Firstly, as long as you
are not trying to use object state loaded in one entity manager in another new entity manager, you
should not need to use merge() at all. Some whole applications will never use this method.
• the application persists these modifications by calling merge() in a second entity manager
• if there is a managed instance with the same identifier currently associated with the persistence
context, copy the state of the given object onto the managed instance
• if there is no managed instance currently associated with the persistence context, try to load it from
the database, or create a new managed instance
• the given instance does not become associated with the persistence context, it remains detached
and is usually discarded
18
Deleting managed objects
3.9.1. In a transaction
From time to time the entity manager will execute the SQL DML statements needed to synchronize
the data store with the state of objects held in memory. This process, flush, occurs by default (this is
Hibernate specific and not defined by the specification) at the following points:
• from javax.persistence.EntityTransaction.commit()*
• all entity insertions, in the same order the corresponding objects were saved using
EntityManager.persist()
• all entity deletions, in the same order the corresponding objects were deleted using
EntityManager.remove()
(Exception: entity instances using application-assigned identifiers are inserted when they are saved.)
Except when you explicity flush(), there are absolutely no guarantees about when the entity
manager executes the JDBC calls, only the order in which they are executed. However, Hibernate
does guarantee that the Query.getResultList()/Query.getSingleResult() will never return
stale data; nor will they return wrong data if executed in an active transaction.
It is possible to change the default behavior so that flush occurs less frequently. The FlushModeType
for an entity manager defines two different modes: only flush at commit time or flush automatically
using the explained routine unless flush() is called explicitly.
19
Chapter 3. Working with objects
em = emf.createEntityManager();
em.getTransaction().begin();
em.setFlushMode(FlushModeType.COMMIT); // allow queries to return stale state
During flush, an exception might happen (e.g. if a DML operation violates a constraint).
Hibernate provides more flush modes than the one described in the EJB3 specification. Please refer to
the Hibernate core reference documentation for more informations.
If the children in a parent/child relationship would be value typed (e.g. a collection of addresses
or strings), their lifecycle would depend on the parent and no further action would be required for
convenient "cascading" of state changes. When the parent is persisted, the value-typed child objects
are persisted as well, when the parent is removed, the children will be removed, etc. This even works
for operations such as the removal of a child from the collection; Hibernate will detect this and, since
value-typed objects can't have shared references, remove the child from the database.
Now consider the same scenario with parent and child objects being entities, not value-types (e.g.
categories and items, or parent and child cats). Entities have their own lifecycle, support shared
references (so removing an entity from the collection does not mean it can be deleted), and there is by
default no cascading of state from one entity to any other associated entities. The EJB3 specification
does not require persistence by reachability. It supports a more flexible model of transitive persistence,
as first seen in Hibernate.
For each basic operation of the entity manager - including persist(), merge(), remove(),
refresh() - there is a corresponding cascade style. Respectively, the cascade styles are named
PERSIST, MERGE, REMOVE, REFRESH. If you want an operation to be cascaded to associated
entity (or collection of entities), you must indicate that in the association annotation:
@OneToOne(cascade=CascadeType.PERSIST)
20
Locking
You may even use CascadeType.ALL to specify that all operations should be cascaded for a particular
association. Remember that by default, no operation is cascaded.
Hibernate offers more native cascading options, please refer to the Hibernate Annotations manual and
the Hibernate reference guide for more informations.
Recommendations:
• If the child object's lifespan is bounded by the lifespan of the parent object,
make the parent a full lifecycle object by specifying CascadeType.ALL and
org.hibernate.annotations.CascadeType.DELETE_ORPHAN (please refer to the Hibernate
reference guide for the semantics of orphan delete)
• Otherwise, you might not need cascade at all. But if you think that you will often be working with the
parent and children together in the same transaction, and you want to save yourself some typing,
consider using cascade={PERSIST, MERGE}. These options can even make sense for a many-
to-many association.
3.11. Locking
The default locking system in EJB3 is mostly based on optimistic locking (ie using a version column
to check any concurrency issues). EJB3 has defined an additional mechanism to increase the
concurrency guaranties. You can apply a lock on a given entity (and it's associated entities if LOCK is
cascaded) through the lock(Object entity) method. Depending on the concurrency guaranties
you requires, you choose a lock mode:
• LockMode.WRITE prevents dirty-reads and non repeatable read on a given entity and force an
increase of the version number if any.
21
22
Chapter 4.
In this chapter, and unless explicitly expressed, we will mix and match the concept of entity manager
and persistence context. One is an API and programming object, the other a definition of scope.
However, keep in mind the essential difference. A persistence context is usually bound to a JTA
transaction in Java EE, and a persistence context starts and ends at transaction boundaries
(transaction-scoped) unless you use an extended entity manager. Please refer to Section 1.2.3,
“Persistence context scope” for more information.
An EntityManager is an inexpensive, non-threadsafe object that should be used once, for a single
business process, a single unit of work, and then discarded. An EntityManager will not obtain
a JDBC Connection (or a Datasource) unless it is needed, so you may safely open and close
an EntityManager even if you are not sure that data access will be needed to serve a particular
request. (This becomes important as soon as you are implementing some of the following patterns
using request interception.)
To complete this picture you also have to think about database transactions. A database transaction
has to be as short as possible, to reduce lock contention in the database. Long database transactions
will prevent your application from scaling to highly concurrent load.
What is the scope of a unit of work? Can a single Hibernate EntityManager span several database
transactions or is this a one-to-one relationship of scopes? When should you open and close a
Session and how do you demarcate the database transaction boundaries?
23
Chapter 4. Transactions and Concurrency
transaction to serve the clients request. The relationship between the two is one-to-one and this model
is a perfect fit for many applications.
This is the default EJB3 persistence model in a Java EE environment (JTA bounded, transaction-
scoped persistence context); injected (or looked up) entity managers share the same persistence
context for a particular JTA transaction. The beauty of EJB3 is that you don't have to care about that
anymore and just see data access through entity manager and demaraction of transaction scope on
session beans as completely orthogonal.
The challenge is the implementation of this (and other) behavior outside an EJB3 container: not
only has the EntityManager and resource-local transaction to be started and ended correctly, but
they also have to be accessible for data access operations. The demarcation of a unit of work is
ideally implemented using an interceptor that runs when a request hits the non-EJB3 container server
and before the response will be send (i.e. a ServletFilter if you are using a standalone servlet
container). We recommend to bind the EntityManager to the thread that serves the request, using a
ThreadLocal variable. This allows easy access (like accessing a static variable) in all code that runs
in this thread. Depending on the database transaction demarcation mechanism you chose, you might
also keep the transaction context in a ThreadLocal variable. The implementation patterns for this
are known as ThreadLocal Session and Open Session in View in the Hibernate community. You can
easily extend the HibernateUtil shown in the Hibernate reference documentation to implement this
pattern, you don't need any external software (it's in fact very trivial). Of course, you'd have to find a
way to implement an interceptor and set it up in your environment. See the Hibernate website for tips
and examples. Once again, remember that your first choice is naturally an EJB3 container - preferably
a light and modular one such as JBoss application server.
• The first screen of a dialog opens, the data seen by the user has been loaded in a particular
EntityManager and resource-local transaction. The user is free to modify the detached objects.
• The user clicks "Save" after 5 minutes and expects his modifications to be made persistent; he also
expects that he was the only person editing this information and that no conflicting modification can
occur.
We call this unit of work, from the point of view of the user, a long running application transaction.
There are many ways how you can implement this in your application.
A first naive implementation might keep the EntityManager and database transaction open during
user think time, with locks held in the database to prevent concurrent modification, and to guarantee
isolation and atomicity. This is of course an anti-pattern, a pessimistic approach, since lock contention
would not allow the application to scale with the number of concurrent users.
Clearly, we have to use several database transactions to implement the application transaction. In this
case, maintaining isolation of business processes becomes the partial responsibility of the application
tier. A single application transaction usually spans several database transactions. It will be atomic
if only one of these database transactions (the last one) stores the updated data, all others simply
read data (e.g. in a wizard-style dialog spanning several request/response cycles). This is easier to
implement than it might sound, especially if you use EJB3 entity manager and persistence context
features:
24
Considering object identity
• Automatic Versioning - An entity manager can do automatic optimistic concurrency control for
you, it can automatically detect if a concurrent modification occured during user think time (usually
by comparing version numbers or timestamps when updating the data in the final resource-local
transaction).
• Detached Entities - If you decide to use the already discussed entity-per-request pattern, all loaded
instances will be in detached state during user think time. The entity manager allows you to merge
the detached (modified) state and persist the modifications, the pattern is called entitymanager-per-
request-with-detached-entities. Automatic versioning is used to isolate concurrent modifications.
• Extended Entity Manager - The Hibernate Entity Manager may be disconnected from the underlying
JDBC connection between two client calls and reconnected when a new client request occurs.
This pattern is known as entitymanager-per-application-transaction and makes even merging
unnecessary. An extend persistence context is responsible to collect and retain any modification
(persist, merge, remove) made outside a transaction. The next client call made inside an active
transaction (typically the last operation of a user conversation) will execute all queued modifications.
Automatic versioning is used to isolate concurrent modifications.
Database Identity
foo.getId().equals( bar.getId() )
JVM Identity
foo==bar
Then for objects attached to a particular persistence context (i.e. in the scope of an EntityManager)
the two notions are equivalent, and JVM identity for database identity is guaranteed by the Hibernate
Entity Manager. However, while the application might concurrently access the "same" (persistent
identity) business object in two different persistence contexts, the two instances will actually be
"different" (JVM identity). Conflicts are resolved using (automatic versioning) at flush/commit time,
using an optimistic approach.
This approach leaves Hibernate and the database to worry about concurrency; it also provides
the best scalability, since guaranteeing identity in single-threaded units of work only doesn't need
expensive locking or other means of synchronization. The application never needs to synchronize on
any business object, as long as it sticks to a single thread per EntityManager. Within a persistence
context, the application may safely use == to compare entities.
However, an application that uses == outside of a persistence context might see unexpected results.
This might occur even in some unexpected places, for example, if you put two detached instances
into the same Set. Both might have the same database identity (i.e. they represent the same row),
but JVM identity is by definition not guaranteed for instances in detached state. The developer has
to override the equals() and hashCode() methods in persistent classes and implement his own
notion of object equality. There is one caveat: Never use the database identifier to implement equality,
use a business key, a combination of unique, usually immutable, attributes. The database identifier
will change if a transient entity is made persistent (see the contract of the persist() operation).
25
Chapter 4. Transactions and Concurrency
If the transient instance (usually together with detached instances) is held in a Set, changing the
hashcode breaks the contract of the Set. Attributes for good business keys don't have to be as stable
as database primary keys, you only have to guarantee stability as long as the objects are in the same
Set. See the Hibernate website for a more thorough discussion of this issue. Also note that this is not
a Hibernate issue, but simply how Java object identity and equality has to be implemented.
• An entity manager is not thread-safe. Things which are supposed to work concurrently, like HTTP
requests, session beans, or Swing workers, will cause race conditions if an EntityManager
instance would be shared. If you keep your Hibernate EntityManager in your HttpSession
(discussed later), you should consider synchronizing access to your Http session. Otherwise, a
user that clicks reload fast enough may use the same EntityManager in two concurrently running
threads. You will very likely have provisions for this case already in place, for other non-threadsafe
but session-scoped objects.
• An exception thrown by the Entity Manager means you have to rollback your database
transaction and close the EntityManager immediately (discussed later in more detail). If your
EntityManager is bound to the application, you have to stop the application. Rolling back the
database transaction doesn't put your business objects back into the state they were at the start of
the transaction. This means the database state and the business objects do get out of sync. Usually
this is not a problem, because exceptions are not recoverable and you have to start over your unit of
work after rollback anyway.
• The persistence context caches every object that is in managed state (watched and checked for
dirty state by Hibernate). This means it grows endlessly until you get an OutOfMemoryException,
if you keep it open for a long time or simply load too much data. One solution for this is some kind
batch processing with regular flushing of the persistence context, but you should consider using a
database stored procedure if you need mass data operations. Some solutions for this problem are
shown in Chapter 6, Batch processing. Keeping a persistence context open for the duration of a
user session also means a high probability of stale data, which you have to know about and control
appropriately.
An EJB3 application can run in non-managed (i.e. standalone, simple Web- or Swing applications)
and managed J2EE environments. In a non-managed environment, an EntityManagerFactory is
usually responsible for its own database connection pool. The application developer has to manually
set transaction boundaries, in other words, begin, commit, or rollback database transactions itself.
A managed environment usually provides container-managed transactions, with the transaction
assembly defined declaratively through annotations of EJB session beans, for example. Programmatic
26
Non-managed environment
transaction demarcation is then no longer necessary, even flushing the EntityManager is done
automatically.
• commit the (resource-local or JTA) transaction (this automatically flushes the entity manager and
persistence context)
• close the entity manager (if using an application-managed entity manager)
• handle exceptions
We'll now have a closer look at transaction demarcation and exception handling in both managed- and
non-managed environments.
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if ( tx != null && tx.isActive() ) tx.rollback();
throw e; // or display error message
}
finally {
em.close();
}
You don't have to flush() the EntityManager explicitly - the call to commit() automatically
triggers the synchronization.
A call to close() marks the end of an EntityManager. The main implication of close() is the
release of resources - make sure you always close and never outside of guaranteed finally block.
You will very likely never see this idiom in business code in a normal application; fatal (system)
exceptions should always be caught at the "top". In other words, the code that executes entity
manager calls (in the persistence layer) and the code that handles RuntimeException (and usually
can only clean up and exit) are in different layers. This can be a challenge to design yourself and
you should use J2EE/EJB container services whenever they are available. Exception handling is
discussed later in this chapter.
4.2.1.1. EntityTransaction
In a JTA environment, you don't need any extra API to interact with the transaction in your
environment. Simply use transaction declaration or the JTA APIs.
If you are using a RESOURCE_LOCAL entity manager, you need to demarcate your transaction
boundaries through the EntityTransaction API. You can get an EntityTransaction through
entityManager.getTransaction(). This EntityTransaction API provides the regular
27
Chapter 4. Transactions and Concurrency
begin(), commit(), rollback() and isActive() methods. It also provide a way to mark
a transaction as rollback only, ie force the transaction to rollback. This is very similar to the JTA
operation setRollbackOnly(). When a commit() operation fail and/or if the transaction is marked
as setRollbackOnly(), the commit() method will try to rollback the transaction and raise a
javax.transaction.RollbackException.
If you use bean-managed transactions (BMT), the code will look like this:
// BMT idiom
@Resource public UserTransaction utx;
@Resource public EntityManagerFactory factory;
// do some work
...
utx.commit();
}
catch (RuntimeException e) {
if (utx != null) utx.rollback();
throw e; // or display error message
}
finally {
em.close();
}
With Container Managed Transactions (CMT) in an EJB3 container, transaction demarcation is done
in session bean annotations or deployment descriptors, not programatically. The EntityManager
will automatically be flushed on transaction completion (and if you have injected or lookup
the EntityManager, it will be also closed automatically). If an exception occurs during the
EntityManager use, transaction rollback occurs automatically if you don't catch the exception. Since
EntityManager exceptions are RuntimeExceptions they will rollback the transaction as per the
EJB specification (system exception vs. application exception).
If you work in a CMT environment, you might also want to use the same entity manager in different
parts of your code. Typically, in a non-managed environment you would use a ThreadLocal variable
to hold the entity manager, but a single EJB request might execute in different threads (e.g. session
bean calling another session bean). The EJB3 container takes care of the persistence context
propagation for you. Either using injection or lookup, the EJB3 container will return an entity manager
with the same persistence context bound to the JTA context if any, or create a new one and bind it
(see Section 1.2.4, “Persistence context propagation” .)
Our entity manager/transaction management idiom for CMT and EJB3 container-use is reduced to
this:
28
Exception handling
In other words, all you have to do in a managed environment is to inject the EntityManager, do your
data access work, and leave the rest to the container. Transaction boundaries are set declaratively in
the annotations or deployment descriptors of your session beans. The lifecycle of the entity manager
and persistence context is completely managed by the container.
When using particular Hibernate native APIs, one caveat has to be remembered: after_statement
connection release mode. Due to a silly limitation of the JTA spec, it is not possible for Hibernate
to automatically clean up any unclosed ScrollableResults or Iterator instances returned
by scroll() or iterate(). You must release the underlying database cursor by calling
ScrollableResults.close() or Hibernate.close(Iterator) explicity from a finally
block. (Of course, most applications can easily avoid using scroll() or iterate() at all from the
CMT code.)
The Hibernate entity manager generally raises exceptions which encapsulate the Hibernate core
exception. Common exceptions raised by the EntityManager API are
The HibernateException, which wraps most of the errors that can occur in a Hibernate
persistence layer, is an unchecked exception. Note that Hibernate might also throw other unchecked
exceptions which are not a HibernateException. These are, again, not recoverable and
appropriate action should be taken.
29
Chapter 4. Transactions and Concurrency
In an EXTENDED persistence context, all read only operations of the entity manager can be
executed outside a transaction (find(), getReference(), refresh(), and read queries).
Some modifications operations can be executed outside a transaction, but they are queued until the
persistence context join a transaction: this is the case of persist(), merge(), remove(). Some
operations cannot be called outside a transaction: flush(), lock(), and update/delete queries.
When a method of the stateful session bean involved or starting a transaction is later called, the
entity manager join the transaction. All queued operation will then be executed to synchronize the
persistence context.
the entity manager join the transaction and all the queued operations will then be executed to
synchronize the persistence context.
30
Application version checking
conflicting updates (and to prevent lost updates). Hibernate provides for three possible approaches to
writing application code that uses optimistic concurrency. The use cases we show are in the context
of long application transactions but version checking also has the benefit of preventing lost updates in
single database transactions.
The version property is mapped using @Version, and the entity manager will automatically
increment it during flush if the entity is dirty.
Of course, if you are operating in a low-data-concurrency environment and don't require version
checking, you may use this approach and just skip the version check. In that case, last commit wins
will be the default strategy for your long application transactions. Keep in mind that this might confuse
the users of the application, as they might experience lost updates without error messages or a
chance to merge conflicting changes.
Clearly, manual version checking is only feasible in very trivial circumstances and not practical for
most applications. Often not only single instances, but complete graphs of modified ojects have to be
checked. Hibernate offers automatic version checking with either detached instances or an extended
entity manager and persistence context as the design paradigm.
In an EXTENDED persistence context, all operations made outside an active transaction are queued.
The EXTENDED persistence context is flushed when executed in an active transaction (at worse at
commit time).
The Entity Manager is disconnected from any underlying JDBC connection when waiting for
user interaction. In an application-managed extended entity manager, this occurs automatically
at transaction completion. In a stateful session bean holding a container-managed extended
entity manager (i.e. a SFSB annotated with @PersistenceContext(EXTENDED)), this occurs
transparently as well. This approach is the most efficient in terms of database access. The application
need not concern itself with version checking or with merging detached instances, nor does it have
to reload instances in every database transaction. For those who might be concerned by the number
31
Chapter 4. Transactions and Concurrency
of connections opened and closed, remember that the connection provider should be a connection
pool, so there is no performance impact. The following examples show the idiom in a non-managed
environment:
The foo object still knows which persistence context it was loaded in. With
getTransaction.begin(); the entity manager obtains a new connection and resumes the
persistence context. The method getTransaction().commit() will not only flush and check
versions, but also disconnects the entity manager from the JDBC connection and return the
connection to the pool.
This pattern is problematic if the persistence context is too big to be stored during user think time, and
if you don't know where to store it. E.g. the HttpSession should be kept as small as possible. As the
persistence context is also the (mandatory) first-level cache and contains all loaded objects, we can
probably use this strategy only for a few request/response cycles. This is indeed recommended, as the
persistence context will soon also have stale data.
It is up to you where you store the extended entity manager during requests, inside an EJB3 container
you simply use a stateful session bean as described above. Don't transfer it to the web layer (or
even serialize it to a separate tier) to store it in the HttpSession. In a non-managed, two-tiered
environment the HttpSession might indeed be the right place to store it.
Again, the entity manager will check instance versions during flush, throwing an exception if conflicting
updates occured.
32
Chapter 5.
A method of the entity may be designated as a callback method to receive notification of a particular
entity life cycle event. Callbacks methods are annotated by a callback annotation. You can also define
an entity listener class to be used instead of the callback methods defined directly inside the entity
class. An entity listener is a stateless class with a no-arg constructor. An entity listener is defined by
annotating the entity class with the @EntityListeners annotation:
@Entity
@EntityListeners(class=Audit.value)
public class Cat {
@Id private Integer id;
private String name;
private Date dateOfBirth;
@Transient private int age;
private Date lastUpdate;
//getters and setters
/**
* Set my transient property at load time based on a calculation,
* note that a native Hibernate formula mapping is better for this purpose.
*/
@PostLoad
public void calculateAge() {
Calendar birth = new GregorianCalendar();
birth.setTime(dateOfBirth);
Calendar now = new GregorianCalendar();
now.setTime( new Date() );
int adjust = 0;
if ( now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) < 0) {
adjust = -1;
}
age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust;
}
}
The same callback method or entity listener method can be annotated with more than one callback
annotation. For a given entity, you cannot have two methods being annotated by the same callback
annotation whether it is a callback method or an entity listener method. A callback method is a no-
arg method with no return type and any arbitrary name. An entity listener has the signature void
<METHOD>(Object) where Object is of the actual entity type (note that Hibernate Entity Manager
relaxed this constraint and allows Object of java.lang.Object type (allowing sharing of listeners
accross several entities.)
33
Chapter 5. Entity listeners and Callback methods
A callback method can raise a RuntimeException. The current transaction, if any, must be rolled
back. The following callbacks are defined:
You can stop the entity listeners inheritance by using the @ExcludeSuperclassListeners, all
superclasses @EntityListeners will then be ignored.
34
XML definition
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
version="1.0"
>
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener
class="org.hibernate.ejb.test.pack.defaultpar.IncrementListener">
<pre-persist method-name="increment"/>
</entity-listener>
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
<package>org.hibernate.ejb.test.pack.defaultpar</package>
<entity class="ApplicationServer">
<entity-listeners>
<entity-listener class="OtherIncrementListener">
<pre-persist method-name="increment"/>
</entity-listener>
</entity-listeners>
<pre-persist method-name="calculate"/>
</entity>
</entity-mappings>
You can override entity listeners on a given entity. An entity listener correspond to a given class and
one or several event fire a given method call. You can also define event on the entity itself to describe
the callbacks.
Last but not least, you can define some default entity listeners that will apply first on the entity listener
stack of all the mapped entities of a given persistence unit. If you don't want an entity to inherit the
default listeners, you can use @ExcludeDefaultListeners (or <exclude-default-listeners/>).
35
36
Chapter 6.
Batch processing
Batch processing has traditionally been difficult in full object/relational mapping. ORM is all about
object state management, which implies that object state is available in memory. However, Hibernate
has some features to optimize batch processing which are discussed in the Hibernate reference guide,
however, EJB3 persistence differs slightly.
The pseudo-syntax for UPDATE and DELETE statements is: ( UPDATE | DELETE ) FROM?
ClassName (WHERE WHERE_CONDITIONS)?. Note that:
String ejbqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = entityManager.createQuery( ejbqlUpdate )
.setParameter( "newName", newName )
.setParameter( "oldName", oldName )
.executeUpdate();
entityManager.getTransaction().commit();
entityManager.close();
To execute an EJB-QL DELETE, use the same Query.executeUpdate() method (the method is
named for those familiar with JDBC's PreparedStatement.executeUpdate()):
The int value returned by the Query.executeUpdate() method indicate the number of entities
affected by the operation. This may or may not correlate with the number of rows affected in the
database. An EJB-QL bulk operation might result in multiple actual SQL statements being executed,
for joined-subclass, for example. The returned number indicates the number of actual entities
affected by the statement. Going back to the example of joined-subclass, a delete against one of the
37
Chapter 6. Batch processing
subclasses may actually result in deletes against not just the table to which that subclass is mapped,
but also the "root" table and potentially joined-subclass tables further down the inheritence hierarchy.
38
Chapter 7.
This manual uses lowercase EJBQL keywords. Some users find queries with uppercase keywords
more readable, but we find this convention ugly when embedded in Java code.
which simply returns all instances of the class eg.Cat. Unlike HQL, the select clause is not optional
in EJB-QL. We don't usually need to qualify the class name, since the entity name defaults to the
unqualified class name (@Entity). So we almost always just write:
As you may have noticed you can assign aliases to classes, the as keywork is optional. An alias
allows you to refer to Cat in other parts of the query.
It is considered good practice to name query aliases using an initial lowercase, consistent with Java
naming standards for local variables (eg. domesticCat).
39
Chapter 7. EJB-QL: The Object Query Language
• inner join
• left outer join
In addition, a "fetch" join allows associations or collections of values to be initialized along with
their parent objects, using a single select. This is particularly useful in the case of a collection. It
effectively overrides the fetching options in the associations and collection mapping metadata. See the
Performance chapter of the Hibernate reference guide for more information.
A fetch join does not usually need to assign an alias, because the associated objects should not be
used in the where clause (or any other clause). Also, the associated objects are not returned directly
in the query results. Instead, they may be accessed via the parent object. The only reason we might
need an alias is if we are recursively join fetching a further collection:
Note that the fetch construct may not be used in queries called using scroll() or iterate().
Nor should fetch be used together with setMaxResults() or setFirstResult(). It is possible
to create a cartesian product by join fetching more than one collection in a query (as in the example
above), be careful the result of this product isn't bigger than you expect. Join fetching multiple
collection roles also sometimes gives unexpected results for bag mappings, so be careful about how
you formulate your queries in this case.
If you are using property-level lazy fetching (with bytecode instrumentation), it is possible to force
Hibernate to fetch the lazy properties immediately (in the first query) using fetch all properties.
This is Hibernate specific option:
select doc from Document doc fetch all properties order by doc.name
select doc from Document doc fetch all properties where lower(doc.name) like '%cats%'
select mate
from Cat as cat
inner join cat.mate as mate
The query will select mates of other Cats. Actually, you may express this query more compactly as:
40
Aggregate functions
Queries may return properties of any value type including properties of component type:
Queries may return multiple objects and/or properties as an array of type Object[],
This is most useful when used together with select new map (HQL specific feature):
41
Chapter 7. EJB-QL: The Object Query Language
• count(*)
• count(...), count(distinct ...), count(all...)
You may use arithmetic operators, concatenation, and recognized SQL functions in the select clause
(depending on configured dialect, HQL specific feature):
The distinct and all keywords may be used and have the same semantics as in SQL.
returns instances not only of Cat, but also of subclasses like DomesticCat. Hibernate queries may
name any Java class or interface in the from clause (portable EJB-QL queries should only name
mapped entities). The query will return instances of all persistent classes that extend that class or
implement the interface. The following query would return all persistent objects:
Note that these last two queries will require more than one SQL SELECT. This means that the order
by clause does not correctly order the whole result set. (It also means you can't call these queries
using Query.scroll().)
select foo
from Foo foo, Bar bar
where foo.startDate = bar.date
42
The where clause
will return all instances of Foo for which there exists an instance of bar with a date property equal to
the startDate property of the Foo. Compound path expressions make the where clause extremely
powerful. Consider:
This query translates to an SQL query with a table (inner) join. If you were to write something like
you would end up with a query that would require four table joins in SQL.
The = operator may be used to compare not only properties, but also instances:
select cat, rival from Cat cat, Cat rival where cat.mate = rival.mate
The special property (lowercase) id may be used to reference the unique identifier of an object. (You
may also use its mapped identifer property name.). Note that this keyword is specific to HQL.
Properties of composite identifiers may also be used. Suppose Person has a composite identifier
consisting of country and medicareNumber.
Likewise, the special property class accesses the discriminator value of an instance in the case of
polymorphic persistence. A Java class name embedded in the where clause will be translated to its
discriminator value. Once again, this is specific to HQL.
You may also specify properties of components or composite user types (and of components of
components, etc). Never try to use a path-expression that ends in a property of component type (as
opposed to a property of a component). For example, if store.owner is an entity with a component
address
store.owner.address.city // okay
43
Chapter 7. EJB-QL: The Object Query Language
store.owner.address // error!
An "any" type has the special properties id and class, allowing us to express a join in the following
way (where AuditLog.item is a property mapped with <any>). Any is specific to Hibernate
Notice that log.item.class and payment.class would refer to the values of completely different
database columns in the above query.
7.8. Expressions
Expressions allowed in the where clause include most of the kind of things you could write in SQL:
• mathematical operators +, -, *, /
• binary comparison operators =, >=, <=, <>, !=, like
• logical operations and, or, not
• Parentheses ( ), indicating grouping
• in, not in, between, is null, is not null, is empty, is not empty, member of and
not member of
• "Simple" case, case ... when ... then ... else ... end, and "searched" case, case
when ... then ... else ... end (specific to HQL)
• string concatenation ...||... or concat(...,...) (use concat() for portable EJB-
QL queries)
• current_date(), current_time(), current_timestamp()
• second(...), minute(...), hour(...), day(...), month(...), year(...), (specific to
HQL)
• Any function or operator defined by EJB-QL 3.0: substring(), trim(), lower(), upper(),
length(), locate(), abs(), sqrt(), bit_length()
• coalesce() and nullif()
• cast(... as ...), where the second argument is the name of a Hibernate type, and
extract(... from ...) if ANSI cast() and extract() is supported by the underlying
database
• Any database-supported SQL scalar function like sign(), trunc(), rtrim(), sin()
• JDBC IN parameters ?
• named parameters :name, :start_date, :x1
• SQL literals 'foo', 69, '1970-01-01 10:00:01.0'
• Java public static final constants eg.Color.TABBY
select cat from DomesticCat cat where cat.name between 'A' and 'B'
select cat from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )
select cat from DomesticCat cat where cat.name not between 'A' and 'B'
select cat from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )
Likewise, is null and is not null may be used to test for null values.
44
Expressions
Booleans may be easily used in expressions by declaring HQL query substitutions in Hibernate
configuration:
This will replace the keywords true and false with the literals 1 and 0 in the translated SQL from
this HQL:
You may test the size of a collection with the special property size, or the special size() function
(HQL specific feature).
For indexed collections, you may refer to the minimum and maximum indices using minindex and
maxindex functions. Similarly, you may refer to the minimum and maximum elements of a collection
of basic type using the minelement and maxelement functions. These are HQL specific features.
select cal from Calendar cal where maxelement(cal.holidays) > current date
The SQL functions any, some, all, exists, in are supported when passed the element or
index set of a collection (elements and indices functions) or the result of a subquery (see below).
While subqueries are supported by EJB-QL, elements and indices are specific HQL features.
Note that these constructs - size, elements, indices, minindex, maxindex, minelement,
maxelement - may only be used in the where clause in Hibernate.
In HQL, elements of indexed collections (arrays, lists, maps) may be referred to by index (in a where
clause only):
45
Chapter 7. EJB-QL: The Object Query Language
HQL also provides the built-in index() function, for elements of a one-to-many association or
collection of values.
If you are not yet convinced by all this, think how much longer and less readable the following query
would be in SQL:
select cust
from Product prod,
Store store
inner join store.customers cust
where prod.name = 'widget'
and store.location.name in ( 'Melbourne', 'Sydney' )
and prod = all elements(cust.currentOrder.lineItems)
46
The order by clause
SQL functions and aggregate functions are allowed in the having and order by clauses, if
supported by the underlying database (eg. not in MySQL).
select cat
from Cat cat
join cat.kittens kitten
group by cat
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) desc
Note that neither the group by clause nor the order by clause may contain arithmetic expressions.
7.11. Subqueries
For databases that support subselects, EJB-QL supports subqueries within queries. A subquery must
be surrounded by parentheses (often by an SQL aggregate function call). Even correlated subqueries
(subqueries that refer to an alias in the outer query) are allowed.
47
Chapter 7. EJB-QL: The Object Query Language
For subqueries with more than one expression in the select list, you can use a tuple constructor:
Note that on some databases (but not Oracle or HSQLDB), you can use tuple constructors in other
contexts, for example when querying components or composite user types:
select cat from Person where name.first = 'Gavin' and name.initial = 'A' and name.last =
'King')
There are two good reasons you might not want to do this kind of thing: first, it is not completely
portable between database platforms; second, the query is now dependent upon the ordering of
properties in the mapping document.
The following query returns the order id, number of items and total value of the order for all unpaid
orders for a particular customer and given minimum total value, ordering the results by total value.
In determining the prices, it uses the current catalog. The resulting SQL query, against the ORDER,
ORDER_LINE, PRODUCT, CATALOG and PRICE tables has four inner joins and an (uncorrelated)
subselect.
48
EJB-QL examples
The next query counts the number of payments in each status, excluding all payments in the
AWAITING_APPROVAL status where the most recent status change was made by the current user.
It translates to an SQL query with two inner joins and a correlated subselect against the PAYMENT,
PAYMENT_STATUS and PAYMENT_STATUS_CHANGE tables.
If the statusChanges collection were mapped as a list instead of a set, the query would be far
simpler.
The next query uses the MS SQL Server isNull() function to return all the accounts and unpaid
payments for the organization to which the current user belongs. It translates to an SQL query with
three inner joins, an outer join and a subselect against the ACCOUNT, PAYMENT, PAYMENT_STATUS,
ACCOUNT_TYPE, ORGANIZATION and ORG_USER tables.
49
Chapter 7. EJB-QL: The Object Query Language
If your database supports subselects, you can place a condition upon selection size in the where
clause of your query:
As this solution can't return a User with zero messages because of the inner join, the following form is
also useful:
50
Chapter 8.
Native query
You may also express queries in the native SQL dialect of your database. This is useful if you want
to utilize database specific features such as query hints or the CONNECT BY option in Oracle. It also
provides a clean migration path from a direct SQL/JDBC based application to Hibernate. Note that
Hibernate allows you to specify handwritten SQL (including stored procedures) for all create, update,
delete, and load operations (please refer to the reference guide for more information.)
@SqlResultSetMapping(name="GetNightAndArea",
entities={
@EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields
= {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id")
}),
@EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields
= {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
}
)
@SqlResultSetMapping(name="defaultSpaceShip",
entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class))
You can also define scalar results and even mix entity results and scalar results
@SqlResultSetMapping(name="ScalarAndEntities",
entities={
@EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class,
fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id")
}),
@EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class,
fields = {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
},
columns={
@ColumnResult(name="durationInSec")
}
)
The SQL query will then have to return a column alias durationInSec.
Please refer to the Hibernate Annotations reference guide for more information about
@SqlResultSetMapping.
51
Chapter 8. Native query
This native query returns nights and area based on the GetNightAndArea result set.
The second version is useful when your SQL query returns one entity reusing the same columns as
the ones mapped in metadata.
Query q = entityManager.createNamedQuery("getSeasonByNativeQuery");
q.setParameter( 1, name );
Season season = (Season) q.getSingleResult();
52
Appendix A. Revision History
Revision 1.1 Tue Oct 27 2009 Laura Bailey [email protected]
Applied changes from JBPAPP-2966, JBPAPP-1723.
53
54