Hibernate.orgCommunity Documentation

Hibernate User Guide

Hibernate - Relational Persistence for Idiomatic Java

5.0.10.Final

2016-07-31


Table of Contents

Preface
1. Architecture
1.1. Overview
1.2. Contextual sessions
2. Domain Model
2.1. POJO Domain Models
2.1.1. Implement a no-argument constructor
2.1.2. Provide identifier attribute(s)
2.1.3. Prefer non-final classes
2.1.4. Declare getters and setters for persistent attributes
2.1.5. Implementing equals() and hashCode()
2.2. Dynamic models
3. Bootstrap
3.1. Native Bootstrapping
3.1.1. Building the ServiceRegistry
3.1.2. Building the Metadata
3.1.3. Building the SessionFactory
3.2. JPA Bootstrapping
3.2.1. JPA-compliant bootstrapping
3.2.2. Proprietary 2-phase bootstrapping
4. Persistence Contexts
4.1. Making entities persistent
4.2. Deleting entities
4.3. Obtain an entity reference without initializing its data
4.4. Obtain an entity with its data initialized
4.5. Obtain an entity by natural-id
4.6. Refresh entity state
4.7. Modifying managed/persistent state
4.8. Working with detached data
4.8.1. Reattaching detached data
4.8.2. Merging detached data
4.9. Checking persistent state
4.10. Accessing Hibernate APIs from JPA
5. Database access
5.1. ConnectionProvider
5.1.1. Using DataSources
5.1.2. Using c3p0
5.1.3. Using Proxool
5.1.4. Using Hikari
5.1.5. Using Hibernate's built-in (and unsupported) pooling
5.1.6. User-provided Connections
5.1.7. ConnectionProvider support for transaction isolation setting
5.2. Database Dialect
6. Transactions and concurrency control
6.1. Physical Transactions
6.1.1. JTA configuration
6.2. Hibernate Transaction API
6.3. Transactional patterns (and anti-patterns)
6.3.1. Session-per-operation anti-pattern
6.3.2. Session-per-request pattern
6.3.3. Conversations
6.3.4. Session-per-application
6.4. Common issues
7. JNDI
8. Locking
8.1. Optimistic
8.1.1. Dedicated version number
8.1.2. Timestamp
8.2. Pessimistic
8.2.1. The LockMode class
9. Fetching
9.1. The basics
9.2. Applying fetch strategies
9.2.1. No fetching
9.2.2. Dynamic fetching via queries
9.2.3. Dynamic fetching via profiles
10. Batching
10.1. JDBC batching
11. Caching
11.1. Configuring second-level caching
11.1.1. RegionFactory
11.1.2. Caching behavior
11.2. Managing the Cached Data
12. Interceptors and events
12.1. Interceptors
12.2. Native Event system
12.2.1. Hibernate declarative security
12.3. JPA Callbacks
13. HQL and JPQL
13.1. Case Sensitivity
13.2. Statement types
13.2.1. Select statements
13.2.2. Update statements
13.2.3. Delete statements
13.2.4. Insert statements
13.3. The FROM clause
13.3.1. Identification variables
13.3.2. Root entity references
13.3.3. Explicit joins
13.3.4. Implicit joins (path expressions)
13.3.5. Collection member references
13.3.6. Polymorphism
13.4. Expressions
13.4.1. Identification variable
13.4.2. Path expressions
13.4.3. Literals
13.4.4. Parameters
13.4.5. Arithmetic
13.4.6. Concatenation (operation)
13.4.7. Aggregate functions
13.4.8. Scalar functions
13.4.9. Collection-related expressions
13.4.10. Entity type
13.4.11. CASE expressions
13.5. The SELECT clause
13.6. Predicates
13.6.1. Relational comparisons
13.6.2. Nullness predicate
13.6.3. Like predicate
13.6.4. Between predicate
13.6.5. In predicate
13.6.6. Exists predicate
13.6.7. Empty collection predicate
13.6.8. Member-of collection predicate
13.6.9. NOT predicate operator
13.6.10. AND predicate operator
13.6.11. OR predicate operator
13.7. The WHERE clause
13.8. Grouping
13.9. Ordering
13.10. Query API
13.10.1. Hibernate Query API
13.10.2. JPA Query API
14. Criteria
14.1. Typed criteria queries
14.1.1. Selecting an entity
14.1.2. Selecting an expression
14.1.3. Selecting multiple values
14.1.4. Selecting a wrapper
14.2. Tuple criteria queries
14.3. FROM clause
14.3.1. Roots
14.3.2. Joins
14.3.3. Fetches
14.4. Path expressions
14.5. Using parameters
15. Native SQL Queries
15.1. Using a SQLQuery
15.1.1. Scalar queries
15.1.2. Entity queries
15.1.3. Handling associations and collections
15.1.4. Returning multiple entities
15.1.5. Returning non-managed entities
15.1.6. Handling inheritance
15.1.7. Parameters
15.2. Named SQL queries
15.2.1. Using return-property to explicitly specify column/alias names
15.2.2. Using stored procedures for querying
15.3. Custom SQL for create, update and delete
15.4. Custom SQL for loading
16. Multi-tenancy
16.1. What is multi-tenancy?
16.2. Multi-tenant data approaches
16.2.1. Separate database
16.2.2. Separate schema
16.2.3. Partitioned (discriminator) data
16.3. Multi-tenancy in Hibernate
16.3.1. MultiTenantConnectionProvider
16.3.2. CurrentTenantIdentifierResolver
16.3.3. Caching
16.3.4. Odds and ends
16.4. Strategies for MultiTenantConnectionProvider implementors
17. OSGi
17.1. OSGi Specification and Environment
17.2. hibernate-osgi
17.3. features.xml
17.4. QuickStarts/Demos
17.5. Container-Managed JPA
17.5.1. Enterprise OSGi JPA Container
17.5.2. persistence.xml
17.5.3. DataSource
17.5.4. Bundle Package Imports
17.5.5. Obtaining an EntityManger
17.6. Unmanaged JPA
17.6.1. persistence.xml
17.6.2. Bundle Package Imports
17.6.3. Obtaining an EntityMangerFactory
17.7. Unmanaged Native
17.7.1. Bundle Package Imports
17.7.2. Obtaining an SessionFactory
17.8. Optional Modules
17.9. Extension Points
17.10. Caveats
18. Envers
18.1. Basics
18.2. Configuration
18.3. Additional mapping annotations
18.4. Choosing an audit strategy
18.5. Revision Log
18.5.1. Tracking entity names modified during revisions
18.6. Tracking entity changes at property level
18.7. Queries
18.7.1. Querying for entities of a class at a given revision
18.7.2. Querying for revisions, at which entities of a given class changed
18.7.3. Querying for revisions of entity that modified given property
18.7.4. Querying for entities modified in a given revision
18.8. Conditional auditing
18.9. Understanding the Envers Schema
18.10. Generating schema with Ant
18.11. Mapping exceptions
18.11.1. What isn't and will not be supported
18.11.2. What isn't and will be supported
18.11.3. @OneToMany+@JoinColumn
18.12. Advanced: Audit table partitioning
18.12.1. Benefits of audit table partitioning
18.12.2. Suitable columns for audit table partitioning
18.12.3. Audit table partitioning example
18.13. Envers links
19. Database Portability Considerations
19.1. Portability Basics
19.2. Dialect
19.3. Dialect resolution
19.4. Identifier generation
19.5. Database functions
19.6. Type mappings
A. Legacy Bootstrapping
A.1. Migration
B. Legacy Hibernate Criteria Queries
B.1. Creating a Criteria instance
B.2. Narrowing the result set
B.3. Ordering the results
B.4. Associations
B.5. Dynamic association fetching
B.6. Components
B.7. Collections
B.8. Example queries
B.9. Projections, aggregation and grouping
B.10. Detached queries and subqueries
B.11. Queries by natural identifier
References

List of Tables

5.1. Provided Dialects
12.1. Callback annotations
15.1. Alias injection names
18.1. Envers Configuration Properties
18.2. Salaries table
18.3. Salaries - audit table

List of Examples

2.1. Scope of identity
2.2. Set usage with Session-scoped identity
2.3. Mixed Sessions
2.4. Sets with transient entities
2.5. Naive equals/hashCode implementation
2.6. Still trouble
2.7. Forcing identifier generation
2.8. Better equals/hashCode with natural-id
2.9. Working with Dynamic Domain Models
3.1. Controlling BootstrapServiceRegistry building
3.2. Building a BootstrapServiceRegistryBuilder
3.3. Controlling StandardServiceRegistry building
3.4. Configuring a MetadataSources
3.5. Configuring a MetadataSources with method chaining
3.6. Building Metadata via MetadataBuilder
3.7. Building SessionFactory via SessionFactoryBuilder
3.8. Native Bootstrapping - Putting it all together
3.9. Injecting a EntityManagerFactory
3.10. Application bootstrapped EntityManagerFactory
4.1. Example of making an entity persistent
4.2. Example of deleting an entity
4.3. Example of obtaining an entity reference without initializing its data
4.4. Example of obtaining an entity reference with its data initialized
4.5. Example of simple natural-id access
4.6. Example of natural-id access
4.7. Example of refreshing entity state
4.8. Example of modifying managed state
4.9. Example of reattaching a detached entity
4.10. Visualizing merge
4.11. Example of merging a detached entity
4.12. Examples of verifying managed state
4.13. Examples of verifying laziness
4.14. Alternative JPA means to verify laziness
4.15. Usage of EntityManager.unwrap
6.1. Using Transaction API in JDBC
6.2. Using Transaction API in JTA (CMT)
6.3. Using Transaction API in JTA (BMT)
8.1. The @Version annotation
8.2. Declaring a version property in hbm.xml
8.3. Using timestamps for optimistic locking
8.4. The timestamp element in hbm.xml
9.1. Sample domain model
9.2. No fetching example
9.3. No fetching (scalar) example
9.4. Dynamic query fetching example
9.5. Fetch profile example
12.1. Custom LoadListener example
12.2. JACC listener registration example
12.3. Example of specifying JPA callbacks
13.1. Example UPDATE query statements
13.2. Example INSERT query statements
13.3. Simple query example
13.4. Simple query using entity name for root entity reference
13.5. Simple query using multiple root entity references
13.6. Explicit inner join examples
13.7. Explicit left (outer) join examples
13.8. Fetch join example
13.9. with-clause join example
13.10. Simple implicit join example
13.11. Reused implicit join
13.12. Collection references example
13.13. Qualified collection references example
13.14. String literal examples
13.15. Numeric literal examples
13.16. Named parameter examples
13.17. Positional (JPQL) parameter examples
13.18. Numeric arithmetic examples
13.19. Concatenation operation example
13.20. Aggregate function examples
13.21. Collection-related expressions examples
13.22. Index operator examples
13.23. Entity type expression examples
13.24. Simple case expression example
13.25. Searched case expression example
13.26. NULLIF example
13.27. Dynamic instantiation example - constructor
13.28. Dynamic instantiation example - list
13.29. Dynamic instantiation example - map
13.30. Relational comparison examples
13.31. ALL subquery comparison qualifier example
13.32. Nullness checking examples
13.33. Like predicate examples
13.34. Between predicate examples
13.35. In predicate examples
13.36. Empty collection expression examples
13.37. Member-of collection expression examples
13.38. Group-by illustration
13.39. Having illustration
13.40. Order-by examples
13.41. Obtaining a Query reference - Hibernate
13.42. Basic Query usage - Hibernate
13.43. Parameter binding - Hibernate
13.44. Parameter binding (inferred type) - Hibernate
13.45. Parameter binding (short forms) - Hibernate
13.46. list() and uniqueResult()
13.47. Obtaining a Query reference - JPA
13.48. Basic Query usage - JPA
13.49. Parameter binding - JPA
14.1. Selecting the root entity
14.2. Selecting an attribute
14.3. Selecting an array
14.4. Selecting an array (2)
14.5. Selecting an wrapper
14.6. Selecting a tuple
14.7. Adding a root
14.8. Adding multiple roots
14.9. Example with Embedded and ManyToOne
14.10. Example with Collections
14.11. Example with Embedded and ManyToOne
14.12. Example with Collections
14.13. Using parameters
15.1. Named sql query using the <sql-query> maping element
15.2. Execution of a named query
15.3. Named sql query with association
15.4. Named query returning a scalar
15.5. <resultset> mapping used to externalize mapping information
15.6. Programmatically specifying the result mapping information
15.7. Named SQL query using @NamedNativeQuery together with @SqlResultSetMapping
15.8. Implicit result set mapping
15.9. Using dot notation in @FieldResult for specifying associations
15.10. Scalar values via @ColumnResult
15.11. Custom CRUD via annotations
15.12. Custom CRUD XML
15.13. Overriding SQL statements for collections using annotations
15.14. Overriding SQL statements for secondary tables
15.15. Stored procedures and their return value
16.1. Specifying tenant identifier from SessionFactory
16.2. Implementing MultiTenantConnectionProvider using different connection pools
16.3. Implementing MultiTenantConnectionProvider using single connection pool
17.1. datasource-h2.xml
17.2. META-INF/persistence.xml
17.3. OSGI-INF/blueprint/blueprint.xml
17.4. Discover/Use EntityManagerFactory
17.5. Discover/Use EntityManagerFactory
17.6. Example extension point registrations in blueprint.xml
18.1. Example of storing username with revision
18.2. Custom implementation of tracking entity classes modified during revisions
A.1. Configuration usage

Developing Object-Oriented software that deals with data from Relational Databases can be cumbersome and resource consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. Hibernate is an Object/Relational Mapping (ORM) solution for Java environments. ORM refers to the technique of mapping data between an object model representation to a relational data model representation. See Wikipedia for a good high-level discussion. Also, Martin Fowler's OrmHate article takes a look at many of the mentioned mismatch problems.

Although having a strong background in SQL is not required to use Hibernate, having a basic understanding of the concepts can help you understand Hibernate more quickly and fully. An understanding of data modeling principles is especially important. Both http://www.agiledata.org/essays/dataModeling101.html and http://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling principles.

Understanding the basics of transactions and design patterns such as "Unit of Work"[PoEAA] or "ApplicationTransaction" are important as well. These topics will be discussed in the documentation, but a prior understanding will certainly help.

Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC. Hibernate’s design goal is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing using SQL and JDBC. However, unlike many other persistence solutions, Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology and knowledge is as valid as always.

Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier. However, Hibernate can certainly help you to remove or encapsulate vendor-specific SQL code and will help with the common task of result set translation from a tabular representation to a graph of objects.

See http://hibernate.org/orm/contribute/ for information on getting involved.

Tip

If you are just getting started with using Hibernate you may want to start with the “Hibernate Getting Started Guide” available from the documentation page. It contains quick-start style tutorials as well as lots of introductory information. There is also a series of topical guides providing deep dives into various topics.

Most applications using Hibernate need some form of "contextual" session, where a given session is in effect throughout the scope of a given context. However, across applications the definition of what constitutes a context is typically different; different contexts define different scopes to the notion of current. Applications using Hibernate prior to version 3.0 tended to utilize either home-grown ThreadLocal-based contextual sessions, helper classes such as HibernateUtil, or utilized third-party frameworks, such as Spring or Pico, which provided proxy/interception-based contextual sessions.

Starting with version 3.0.1, Hibernate added the SessionFactory.getCurrentSession() method. Initially, this assumed usage of JTA transactions, where the JTA transaction defined both the scope and context of a current session. Given the maturity of the numerous stand-alone JTA TransactionManager implementations, most, if not all, applications should be using JTA transaction management, whether or not they are deployed into a J2EE container. Based on that, the JTA-based contextual sessions are all you need to use.

However, as of version 3.1, the processing behind SessionFactory.getCurrentSession() is now pluggable. To that end, a new extension interface, org.hibernate.context.spi.CurrentSessionContext, and a new configuration parameter, hibernate.current_session_context_class, have been added to allow pluggability of the scope and context of defining current sessions.

See the Javadocs for the org.hibernate.context.spi.CurrentSessionContext interface for a detailed discussion of its contract. It defines a single method, currentSession(), by which the implementation is responsible for tracking the current contextual session. Out-of-the-box, Hibernate comes with three implementations of this interface:

  • org.hibernate.context.internal.JTASessionContext: current sessions are tracked and scoped by a JTA transaction. The processing here is exactly the same as in the older JTA-only approach. See the Javadocs for details.

  • org.hibernate.context.internal.ThreadLocalSessionContext:current sessions are tracked by thread of execution. See the Javadocs for details.

  • org.hibernate.context.internal.ManagedSessionContext: current sessions are tracked by thread of execution. However, you are responsible to bind and unbind a Session instance with static methods on this class: it does not open, flush, or close a Session.

Typically, the value of this parameter would just name the implementation class to use. For the three out-of-the-box implementations, however, there are three corresponding short names: "jta", "thread", and "managed".

The first two implementations provide a "one session - one database transaction" programming model. This is also known and used as session-per-request. The beginning and end of a Hibernate session is defined by the duration of a database transaction. If you use programmatic transaction demarcation in plain JSE without JTA, you are advised to use the Hibernate Transaction API to hide the underlying transaction system from your code. If you use JTA, you can utilize the JTA interfaces to demarcate transactions. If you execute in an EJB container that supports CMT, transaction boundaries are defined declaratively and you do not need any transaction or session demarcation operations in your code. Refer to Chapter 6, Transactions and concurrency control for more information and code examples.

The hibernate.current_session_context_class configuration parameter defines which org.hibernate.context.spi.CurrentSessionContext implementation should be used. For backwards compatibility, if this configuration parameter is not set but a org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform is configured, Hibernate will use the org.hibernate.context.internal.JTASessionContext.

The term domain model comes from the realm of data modeling. It is the model that ultimately describes the problem domain you are working in. Sometimes you will also hear the term "persistent classes".

Ultimately the application's domain model is the central character in an ORM. They make up the classes you wish to map. Hibernate works best if these classes follow the Plain Old Java Object (POJO) / JavaBean programming model. However, none of these rules are hard requirements. Indeed, Hibernate assumes very little about the nature of your persistent objects. You can express a domain model in other ways (using trees of java.util.Map instances, for example).

Note

Even though Hibernate does not consider all of these rules as hard requirements, JPA does specify some of them. Therefore, if you are concerned about JPA provider portability it is best to stick to the strict POJO model. We will point out these concerns where applicable.

This chapter will describe the characteristics of a persistable domain model. However, it will not discuss defining the mapping for the domain model. That is a massive topic in its own right and is the subject of an entire dedicated manual. See the Hibernate Domain Model Mapping Guide from the documentation site.

This section explores domain models defined as POJOs.

Whether to implement equals() and hashCode() methods in your domain model, let alone how to implement them, is a surprisingly tricky discussion when it comes to ORM.

There is really just one absolute case: a class that acts as an identifier must implement equals/hashCode based on the id value(s). Generally this is pertinent for user classes used as composite identifiers. Beyond this one absolute case and the few others we will discuss below, you may want to consider not implementing equals/hashCode.

So what's all the fuss? Normally, most Java objects provide a built-in equals() and hashCode() based on the object's identity, so each new object will be different from all others. This is generally what you want in ordinary Java programming. Conceptually however this starts to break down when you start to think about the possibility multiple instances of a class representing the same data which is in fact the case when we start dealing with data from a database. Every time we load a specific Person from the database we would naturally get a unique instance. Hibernate, however, works hard to make sure that does not happen within a given Session. In fact Hibernate guarantees equivalence of persistent identity (database row) and Java identity inside a particular session scope. So if we ask a Hibernate Session to load that specific Person multiple times we will actually get back the same instance:


Consider another example using a persistent java.util.Set:


However, the semantic changes when we mix instances loaded from different Sessions:


Specifically the outcome in this last example will depend on whether the Person class implemented equals/hashCode, and if so how.

Consider yet another case:


In cases where you will be dealing with entities outside of a Session (whether they be transient or detached), especially in cases where you will be using them in Java collections, you should consider implementing equals/hashCode.

A common initial approach is to use the entity's identifier attribute as the basis for equals/hashCode calculations:


It turns out that this still breaks when adding transient instance of Person to a set as we saw in the last example:


The issue here is a conflict between (1) the use of generated identifier and (2) the contract of Set and (3) the equals/hashCode implementations. Set says that the equals/hashCode value for an object should not change while it is part of the Set. But that is exactly what happened here because the equals/hasCode are based on the (generated) id, which was not set until the session.getTransaction().commit() call.

Note that this is just a concern when using generated identifiers. If you are using assigned identifiers this will not be a problem, assuming the identifier value is assigned prior to adding to the Set.

Another option is to force the identifier to be generated and set prior to adding to the Set:


But this is often not feasible.

The final approach is to use a "better" equals/hashCode implementation, making use of a natural-id or business-key.


As you can see the question of equals/hashCode is not trivial. Nor is there a one-size-fits-all solution.

Persistent entities do not necessarily have to be represented as POJO/JavaBean classes. Hibernate also supports dynamic models (using Maps of Maps at runtime). With this approach, you do not write persistent classes, only mapping files.

Note

The mapping of dynamic models is beyond the scope of this document. We will discuss using such models with Hibernate, but for mapping see the Hibernate Domain Model Mapping documentation.

A given entity has just one entity mode within a given SessionFactory. This is a change from previous versions which allowed to define multiple entity modes for an entity and to select which to load. Entity modes can now also be mixed within a domain model; a dynamic entity might reference a POJO entity, and vice versa.


The main advantage of dynamic models is quick turnaround time for prototyping without the need for entity class implementation. The main down-fall is that you lose compile-time type checking and will likely deal with many exceptions at runtime. However, as a result of the Hibernate mapping, the database schema can easily be normalized and sound, allowing to add a proper domain model implementation on top later on.

It is also interesting to note that dynamic models are great for certain integration use cases as well. Envers, for example, makes extensive use of dynamic models to represent the historical data.

The term bootstrapping refers to initializing and starting a software component. In Hibernate we are specifically talking about the process of building a fully functional SessionFactory instance or EntityManagerFactory instance for JPA. The process is very different for each.

Note

This chapter will not focus on all the possibilities of bootstrapping. Those will be covered in each specific more-relevant chapters later on. Instead we focus here on the API calls needed to perform the bootstrapping.

This section discusses the process of bootstrapping a Hibernate SessionFactory. Specifically it discusses the bootstrapping APIs as redesigned in 5.0. For a discussion of the legacy bootstrapping API, see Appendix A, Legacy Bootstrapping

The first step in native bootstrapping is the building of a ServiceRegistry holding the services Hibernate will need at bootstrap and run time.

Actually we are concerned with building 2 different ServiceRegistries. First is the org.hibernate.boot.registry.BootstrapServiceRegistry. The BootstrapServiceRegistry is intended to hold services that Hibernate needs at both bootstrap and run time. This boils down to 3 services:

  • org.hibernate.boot.registry.classloading.spi.ClassLoaderService - which controls how Hibernate interacts with ClassLoaders

  • org.hibernate.integrator.spi.IntegratorService - which controls the management ands discovery of org.hibernate.integrator.spi.Integrator instances.

  • org.hibernate.boot.registry.selector.spi.StrategySelector - which control how Hibernate resolves implementations of various strategy contracts. This is a very powerful service, but a full discussion of it is beyond the scope of this guide.

If you are ok with the default behavior of Hibernate in regards to these BootstrapServiceRegistry services (which is quite often the case, especially in SE environments), then building the BootstrapServiceRegistry can be skipped.

If you wish to alter how the BootstrapServiceRegistry is built, that is controlled through the org.hibernate.boot.registry.BootstrapServiceRegistryBuilder:


The services of the BootstrapServiceRegistry cannot be extended (added to) nor overridden (replaced).

The second ServiceRegistry is the org.hibernate.boot.registry.StandardServiceRegistry. You will almost always need to configure the StandardServiceRegistry, which is done through org.hibernate.boot.registry.StandardServiceRegistryBuilder:


A StandardServiceRegistry is also highly configurable via the StandardServiceRegistryBuilder API. See the StandardServiceRegistryBuilder javadocs for full details. Some specific methods of interest:


The second step in native bootstrapping is the building of a org.hibernate.boot.Metadata object containing the parsed representations of an application's domain model and its mapping to a database. The first thing we obviously need to build a parsed representation is the source information to be parsed (annotated classes, `hbm.xml` files, `orm.xml` files). This is the purpose of org.hibernate.boot.MetadataSources:


MetadataSources has many other methods as well; explore its API and javadocs for more information. Also, all methods on MetadataSources allow for chaining should you prefer that style:


Once we have the sources of mapping information defined, we need to build the Metadata object. If you are ok with the default behavior in building the Metadata then you can simply call MetadataSources#buildMetadata.

Note

Notice that a ServiceRegistry can be passed at a number of points in this bootstrapping process. The suggested approach is to build a StandardServiceRegistry yourself and pass that along to the MetadataSources constructor. From there, MetadataBuilder, Metadata, SessionFactoryBuilder and SessionFactory will all pick up that same StandardServiceRegistry.

However, if you wish to adjust the process of building Metadata from MetadataSources you will need to use the MetadataBuilder as obtained via MetadataSources#getMetadataBuilder. MetadataBuilder allows a lot of control over the Metadata building process. See its javadocs for full details.


The final step in native bootstrapping is to build the SessionFactory itself. Much like discussed above, if you are ok with the default behavior of building a SessionFactory from a Metadata reference, you can simply call Metadata#buildSessionFactory.

However, if you would like to adjust that building process you will need to use SessionFactoryBuilder as obtained via Metadata#getSessionFactoryBuilder. Again, see its javadocs for full details.


The bootstrapping API is quite flexible, but in most cases it makes the most sense to think of it as a 3 step process:

  1. Build the StandardServiceRegistry
  2. Build the Metadata
  3. Use those 2 things to build the SessionFactory


Bootstrapping Hibernate as a JPA provider can be done in a JPA-spec compliant manner or using a proprietary bootstrapping approach. The standardized approach has some limitations in certain environments, but aside from those limitations, it is *highly* recommended that you use JPA-standardized bootstrapping.

In JPA we are ultimately interested in bootstrapping an javax.persistence.EntityManagerFactory instance. The JPA specification defines 2 primary standardized bootstrap approaches depending on how the application intends to access the javax.persistence.EntityManager instances from an EntityManagerFactory. It uses the terms "EE" and "SE" for these 2 approaches, but those terms are very misleading in this context. What the JPA spec calls EE bootstrapping is cases where a container (EE, OSGi, etc) will manage and inject the persistence context on behalf of the application. What it calls SE bootstrapping is everything else. We will use the terms container-bootstrapping and application-bootstrapping in this guide.

Both the org.hibernate.Session API and javax.persistence.EntityManager API represent a context for dealing with persistent data. This concept is called a persistence context. Persistent data has a state in relation to both a persistence context and the underlying database.

Entity states

  • transient - the entity has just been instantiated and is not associated with a persistence context. It has no persistent representation in the database and typically no identifier value has been assigned.

  • managed, or persistent - the entity has an associated identifier and is associated with a persistence context. It may or may not physically exist in the database yet.

  • detached - the entity has an associated identifier, but is no longer associated with a persistence context (usually because the persistence context was closed or the instance was evicted from the context)

  • removed - the entity has an associated identifier and is associated with a persistence context, however it is scheduled for removal from the database.

Much of the org.hibernate.Session and javax.persistence.EntityManager methods deal with moving entities between these states.

In addition to allowing to load by identifier, Hibernate allows applications to load by declared natural identifier.



Just like we saw above, access entity data by natural id allows both the load and getReference forms, with the same semantics.

Accessing persistent data by identifier and by natural-id is consistent in the Hibernate API. Each defines the same 2 data access methods:

getReference

Should be used in cases where the identifier is assumed to exist, where non-existence would be an actual error. Should never be used to test existence. That is because this method will prefer to create and return a proxy if the data is not already associated with the Session rather than hit the database. The quintessential use-case for using this method is to create foreign-key based associations.

load

Will return the persistent data associated with the given identifier value or null if that identifier does not exist.

In addition to those 2 methods, each also defines the method with accepting a org.hibernate.LockOptions argument. Locking is discussed in a separate chapter.

Detachment is the process of working with data outside the scope of any persistence context. Data becomes detached in a number of ways. Once the persistence context is closed, all data that was associated with it becomes detached. Clearing the persistence context has the same effect. Evicting a particular entity from the persistence context makes it detached. And finally, serialization will make the deserialized form be detached (the original instance is still managed).

Detached data can still be manipulated, however the persistence context will no longer automatically know about these modification and the application will need to intervene to make the changes persistent.

An application can verify the state of entities and collections in relation to the persistence context.



In JPA there is an alternative means to check laziness using the following javax.persistence.PersistenceUtil pattern. However, the javax.persistence.PersistenceUnitUtil is recommended where ever possible


As an ORM tool, probably the single most important thing you need to tell Hibernate is how to connect to your database so that it may connect on behalf of your application. This is ultimately the function of the org.hibernate.engine.jdbc.connections.spi.ConnectionProvider interface. Hibernate provides some out of the box implementations of this interface. ConnectionProvider is also an extension point, so you can also use custom implementations from third parties or written yourself. The ConnectionProvider to use is defined by the hibernate.connection.provider_class setting. See the org.hibernate.cfg.AvailableSettings#CONNECTION_PROVIDER

Generally speaking applications should not have to configure a ConnectionProvider explicitly if using one of the Hibernate-provided implementations. Hibernate will internally determine which ConnectionProvider to use based on the following algorithm:

Hibernate can integrate with a javax.sql.DataSource for obtaining JDBC Connections. Applications would tell Hibernate about the DataSource via the (required) hibernate.connection.datasource setting which can either specify a JNDI name or would reference the actual DataSource instance. For cases where a JNDI name is given, be sure to read Chapter 7, JNDI

Note

For JPA applications, note that hibernate.connection.datasource corresponds to either javax.persistence.jtaDataSource or javax.persistence.nonJtaDataSource.

The DataSource ConnectionProvider also (optionally) accepts the hibernate.connection.username and hibernate.connection.password. If specified, the form of DataSource#getConnection accepting username and password will be used. Otherwise the no-arg form is used.

Important

To use this integration, the application must include the hibernate-c3p0 module jar (as well as its dependencies) on the classpath.

Hibernate also provides support for applications to use c3p0 connection pooling. When using this c3p0 support, a number of additional configuration settings are recognized.

Transaction isolation of the Connections is managed by the ConnectionProvider itself. See Section 5.1.7, “ConnectionProvider support for transaction isolation setting”.

Additional settings

hibernate.connection.driver_class

The name of the JDBC Driver class to use

hibernate.connection.url

The JDBC connection url.

Any settings prefixed with hibernate.connection. (other than the "special ones")

These all have the hibernate.connection. prefix stripped and the rest will be passed as JDBC connection properties

hibernate.c3p0.min_size or c3p0.minPoolSize

The minimum size of the c3p0 pool. See http://www.mchange.com/projects/c3p0/#minPoolSize

hibernate.c3p0.max_size or c3p0.maxPoolSize

The maximum size of the c3p0 pool. See http://www.mchange.com/projects/c3p0/#maxPoolSize

hibernate.c3p0.timeout or c3p0.maxIdleTime

The Connection idle time. See http://www.mchange.com/projects/c3p0/#maxIdleTime

hibernate.c3p0.max_statements or c3p0.maxStatements

Controls the c3p0 PreparedStatement cache size (if using). See http://www.mchange.com/projects/c3p0/#maxStatements

hibernate.c3p0.acquire_increment or c3p0.acquireIncrement

Number of connections c3p0 should acquire at a time when pool is exhauted. See http://www.mchange.com/projects/c3p0/#acquireIncrement

hibernate.c3p0.idle_test_period or c3p0.idleConnectionTestPeriod

Idle time before a c3p0 pooled connection is validated. See http://www.mchange.com/projects/c3p0/#idleConnectionTestPeriod

c3p0.initialPoolSize

The initial c3p0 pool size. If not specified, default is to use the min pool size. See http://www.mchange.com/projects/c3p0/#initialPoolSize

Any other settings prefixed with hibernate.c3p0.

Will have the hibernate. portion stripped and be passed to c3p0.

Any other settings prefixed with c3p0.

Get passed to c3p0 as is. See http://www.mchange.com/projects/c3p0/#configuration

Important

To use this integration, the application must include the hibernate-hikari module jar (as well as its dependencies) on the classpath.

Hibernate also provides support for applications to use Hikari connection pool.

Set all of your Hikari settings in Hibernate prefixed by hibernate.hikari. and this ConnectionProvider will pick them up and pass them along to Hikari. Additionally, this ConnectionProvider will pick up the following Hibernate-specific properties and map them to the corresponding Hikari ones (any hibernate.hikari. prefixed ones have precedence):

Hibernate-specific properties recognized by Hikari ConnectionProvider

hibernate.connection.driver_class

Mapped to Hikari's driverClassName setting

hibernate.connection.url

Mapped to Hikari's jdbcUrl setting

hibernate.connection.username

Mapped to Hikari's username setting

hibernate.connection.password

Mapped to Hikari's password setting

hibernate.connection.isolation

Mapped to Hikari's transactionIsolation setting. See Section 5.1.7, “ConnectionProvider support for transaction isolation setting”. Note that Hikari only supports JDBC standard isolation levels (apparently).

hibernate.connection.autocommit

Mapped to Hikari's autoCommit setting

Although SQL is relatively standardized, each database vendor uses a subset and superset of ANSI SQL defined syntax. This is referred to as the database's dialect. Hibernate handles variations across these dialects through its org.hibernate.dialect.Dialect class and the various subclasses for each database vendor.

In most cases Hibernate will be able to determine the proper Dialect to use by asking some questions of the JDBC Connection during bootstrap. For information on Hibernate's ability to determine the proper Dialect to use (and your ability to influence that resolution), see Section 19.3, “Dialect resolution”

If for some reason it is not able to determine the proper one or you want to use a custom Dialect, you will need to set the hibernate.dialect setting.

Table 5.1. Provided Dialects

Dialect (short name)Remarks
Cache71 Support for the CachÉ database, version 2007.1
CUBRID Support for the CUBRID database, version 8.3. May work with later versions.
DB2 Support for the DB2 database
DB2390 Support for DB2 Universal Database for OS/390, also known as DB2/390.
DB2400 Support for DB2 Universal Database for iSeries, also known as DB2/400.
DerbyTenFive Support for the Derby database, version 10.5
DerbyTenSix Support for the Derby database, version 10.6
DerbyTenSeven Support for the Derby database, version 10.7
Firebird Support for the Firebird database
FrontBase Support for the Frontbase database
H2 Support for the H2 database
HSQL Support for the HSQL (HyperSQL) database
Informix Support for the Informix database
Ingres Support for the Ingres database, version 9.2
Ingres9 Support for the Ingres database, version 9.3. May work with newer versions
Ingres10 Support for the Ingres database, version 10. May work with newer versions
Interbase Support for the Interbase database.
JDataStore Support for the JDataStore database
McKoi Support for the McKoi database
Mimer Support for the Mimer database, version 9.2.1. May work with newer versions
MySQL5 Support for the MySQL database, version 5.x
MySQL5InnoDB Support for the MySQL database, version 5.x preferring the InnoDB storage engine when exporting tables.
MySQL57InnoDB Support for the MySQL database, version 5.7 preferring the InnoDB storage engine when exporting tables. May work with newer versions
Oracle8i Support for the Oracle database, version 8i
Oracle9i Support for the Oracle database, version 9i
Oracle10g Support for the Oracle database, version 10g
Pointbase Support for the Pointbase database
PostgresPlus Support for the Postgres Plus database
PostgreSQL81 Support for the PostgrSQL database, version 8.1
PostgreSQL82 Support for the PostgreSQL database, version 8.2
PostgreSQL9 Support for the PostgreSQL database, version 9. May work with later versions.
Progress Support for the Progress database, version 9.1C. May work with newer versions.
SAPDB Support for the SAPDB/MAXDB database.
SQLServer Support for the SQL Server 2000 database
SQLServer2005 Support for the SQL Server 2005 database
SQLServer2008 Support for the SQL Server 2008 database
Sybase11 Support for the Sybase database, up to version 11.9.2
SybaseAnywhere Support for the Sybase Anywhere database
SybaseASE15 Support for the Sybase Adaptive Server Enterprise database, version 15
SybaseASE157 Support for the Sybase Adaptive Server Enterprise database, version 15.7. May work with newer versions.
Teradata Support for the Teradata database
TimesTen Support for the TimesTen database, version 5.1. May work with newer versions

It is important to understand that the term transaction has many different yet related meanings in regards to persistence and Object/Relational Mapping. In most use-cases these definitions align, but that is not always the case.

  • Might refer to the physical transaction with the database.

  • Might refer to the logical notion of a transaction as related to a persistence context.

  • Might refer to the application notion of a Unit-of-Work, as defined by the archetypal pattern.

Note

This documentation largely treats the physical and logic notions of transaction as one-in-the-same.

Hibernate uses the JDBC API for persistence. In the world of Java there are 2 well defined mechanism for dealing with transactions in JDBC: JDBC itself and JTA. Hibernate supports both mechanisms for integrating with transactions and allowing applications to manage physical transactions.

Transaction handling per Session is handled by the org.hibernate.resource.transaction.TransactionCoordinator contract, which are built by the org.hibernate.resource.transaction.TransactionCoordinatorBuilder service. TransactionCoordinatorBuilder represents a strategy for dealing with transactions whereas TransactionCoordinator represents one instance of that strategy related to a Session. Which TransactionCoordinatorBuilder implementation to use is defined by the hibernate.transaction.coordinator_class setting.

Note

For details on implementing a custom TransactionCoordinatorBuilder, or simply better understanding how it works, see the Integrations Guide

Hibernate uses JDBC connections and JTA resources directly, without adding any additional locking behavior. Hibernate does not lock objects in memory. The behavior defined by the isolation level of your database transactions does not change when you use Hibernate. The Hibernate Session acts as a transaction-scoped cache providing repeatable reads for lookup by identifier and queries that result in loading entities.

Important

To reduce lock contention in the database, the physical database transaction needs to be as short as possible. Long database transactions prevent your application from scaling to a highly-concurrent load. Do not hold a database transaction open during end-user-level work, but open it after the end-user-level work is finished. This is concept is referred to as transactional write-behind.

Interaction with a JTA system is consolidated behind a single contract named org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform which exposes access to the javax.transaction.TransactionManager and javax.transaction.UserTransaction for that system as well as exposing the ability to register javax.transaction.Synchronization instances, check transaction status, etc.

Hibernate tries to discover the JtaPlatform it should use through the use of another service named org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver. If that resolution does not work, or if you wish to provide a custom implementation you will need to specify the hibernate.transaction.jta.platform setting. Hibernate provides many implementations of the JtaPlatform contract, all with short-names:

Built-in JtaPlatform implementations by short name

  • Borland - JtaPlatform for the Borland Enterprise Server.

  • Bitronix - JtaPlatform for Bitronix.

  • JBossAS - JtaPlatform for Arjuna/JBossTransactions/Narnya when used within the JBoss/WildFly Application Server.

  • JBossTS - JtaPlatform for Arjuna/JBossTransactions/Narnya when used standalone.

  • JOnAS - JtaPlatform for JOTM when used within JOnAS.

  • JOTM - JtaPlatform for JOTM when used standalone.

  • JRun4 - JtaPlatform for the JRun 4 Application Server.

  • OC4J - JtaPlatform for Oracle's OC4J container.

  • Orion - JtaPlatform for the Orion Application Server.

  • Resin - JtaPlatform for the Resin Application Server.

  • SunOne - JtaPlatform for the SunOne Application Server.

  • Weblogic - JtaPlatform for the Weblogic Application Server.

  • WebSphere - JtaPlatform for older versions of the WebSphere Application Server.

  • WebSphereExtended - JtaPlatform for newer versions of the WebSphere Application Server.

Hibernate provides an API for helping to isolate applications from the differences in the underlying physical transaction system in use. Based on the configured TransactionCoordinatorBuilder, Hibernate will simply do the right thing when this transaction API is used by the application. This allows your applications and components to be more portable move around into different environments.

To use this API, you would obtain the org.hibernate.Transaction from the Session.

Transaction allows for all the normal operations you'd expect. begin, commit and rollback. And these calls noop if they should.

It even exposes some cool methods like:

  • markRollbackOnly that works in both JTA and JDBC!
  • getTimeout and setTimeout that again work in both JTA and JDBC!
  • registerSynchronization that allows you to register JTA Synchronizations even in non-JTA environments. In fact in both JTA and JDBC environments, these Synchronizations are kept locally by Hibernate. In JTA environments Hibernate will only ever register one single Synchronization with the TransactionManager to avoid ordering problems.

Additionally it exposes a getStatus method that returns an org.hibernate.resource.transaction.spi.TransactionStatus enum. This method checks with the underling transaction system if needed, so care should be taken to minimize its use; it can have a big performance impact in certain JTA set ups.

Lets take a look at using the Transaction API in the various environments.




In the CMT case we really could have omitted all of the Transaction calls. But the point of the examples was to show that the Transaction API really does insulate your code from the underlying transaction mechanism. In fact if you strip away the comments and the single configruation setting supplied at bootstrap, the code is exactly the same in all 3 examples. In other words, we could develop that code and drop it, as-is, in any of the 3 transaction environments.

The Transaction API tries hard to make the experience consistent across all environments. To that end, it generally defers to the JTA specification when there are differences (for example automatically trying rollback on a failed commit).

This is the most common transaction pattern. The term request here relates to the concept of a system that reacts to a series of requests from a client/user. Web applications are a prime example of this type of system, though certainly not the only one. At the beginning of handling such a request, the application opens a Hibernate Session, starts a transaction, performs all data related work, ends the transaction and closes the Session. The crux of the pattern is the one-to-one relationship between the transaction and the Session.

Within this pattern there is a common technique of defining a current session to simplify the need of passing this Session around to all the application components that may need access to it. Hibernate provides support for this technique through the getCurrentSession method of the SessionFactory. The concept of a "current" session has to have a scope that defines the bounds in which the notion of "current" is valid. This is purpose of the org.hibernate.context.spi.CurrentSessionContext contract. There are 2 reliable defining scopes:

  • First is a JTA transaction because it allows a callback hook to know when it is ending which gives Hibernate a chance to close the Session and clean up. This is represented by the org.hibernate.context.internal.JTASessionContext implementation of the org.hibernate.context.spi.CurrentSessionContext contract. Using this implementation, a Session will be opened the first time getCurrentSession is called within that transaction.

  • Secondly is this application request cycle itself. This is best represented with the org.hibernate.context.internal.ManagedSessionContext implementation of the org.hibernate.context.spi.CurrentSessionContext contract. Here an external component is responsible for managing the lifecycle and scoping of a "current" session. At the start of such a scope, ManagedSessionContext's bind method is called passing in the Session. At the end, its unbind method is called.

    Some common examples of such "external components" include:

    • javax.servlet.Filter implementation

    • AOP interceptor with a pointcut on the service methods

    • A proxy/interception container

Important

The getCurrentSession() method has one downside in a JTA environment. If you use it, after_statement connection release mode is also used by default. Due to a limitation of the JTA specification, Hibernate cannot automatically clean up any unclosed ScrollableResults or Iterator instances returned by scroll() or iterate(). Release the underlying database cursor by calling ScrollableResults.close() or Hibernate.close(Iterator) explicitly from a finally block.

The session-per-request pattern is not the only valid way of designing units of work. Many business processes require a whole series of interactions with the user that are interleaved with database accesses. In web and enterprise applications, it is not acceptable for a database transaction to span a user interaction. Consider the following example:

Even though we have multiple databases access here, from the point of view of the user, this series of steps represents a single unit of work. There are many ways to implement this in your application.

A first naive implementation might keep the Session and database transaction open while the user is editing, using database-level locks to prevent other users from modifying the same data and to guarantee isolation and atomicity. This is an anti-pattern, because lock contention is a bottleneck which will prevent scalability in the future.

Several database transactions are used to implement the conversation. In this case, maintaining isolation of business processes becomes the partial responsibility of the application tier. A single conversation usually spans several database transactions. These multiple database accesses can only be atomic as a whole if only one of these database transactions (typically the last one) stores the updated data. All others only read data. A common way to receive this data is through a wizard-style dialog spanning several request/response cycles. Hibernate includes some features which make this easy to implement.

Automatic Versioning

Hibernate can perform automatic optimistic concurrency control for you. It can automatically detect if a concurrent modification occurred during user think time. Check for this at the end of the conversation.

Detached Objects

If you decide to use the session-per-request pattern, all loaded instances will be in the detached state during user think time. Hibernate allows you to reattach the objects and persist the modifications. The pattern is called session-per-request-with-detached-objects. Automatic versioning is used to isolate concurrent modifications.

Extended Session

The Hibernate Session can be disconnected from the underlying JDBC connection after the database transaction has been committed and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary. Automatic versioning is used to isolate concurrent modifications and the Session will not be allowed to flush automatically, only explicitly.

Session-per-request-with-detached-objects and session-per-conversation each have advantages and disadvantages.

Locking refers to actions taken to prevent data in a relational database from changing between the time it is read and the time that it is used.

Your locking strategy can be either optimistic or pessimistic.

Locking strategies

Optimistic

Optimistic locking assumes that multiple transactions can complete without affecting each other, and that therefore transactions can proceed without locking the data resources that they affect. Before committing, each transaction verifies that no other transaction has modified its data. If the check reveals conflicting modifications, the committing transaction rolls back[1].

Pessimistic

Pessimistic locking assumes that concurrent transactions will conflict with each other, and requires resources to be locked after they are read and only unlocked after the application has finished using the data.

Hibernate provides mechanisms for implementing both types of locking in your applications.

When your application uses long transactions or conversations that span several database transactions, you can store versioning data, so that if the same entity is updated by two conversations, the last to commit changes is informed of the conflict, and does not override the other conversation's work. This approach guarantees some isolation, but scales well and works particularly well in Read-Often Write-Sometimes situations.

Hibernate provides two different mechanisms for storing versioning information, a dedicated version number or a timestamp.

Version number

Timestamp

Note

A version or timestamp property can never be null for a detached instance. Hibernate detects any instance with a null version or timestamp as transient, regardless of other unsaved-value strategies that you specify. Declaring a nullable version or timestamp property is an easy way to avoid problems with transitive reattachment in Hibernate, especially useful if you use assigned identifiers or composite keys.

The version number mechanism for optimistic locking is provided through a @Version annotation.


The version column can be any kind of type, as long as you define and implement the appropriate UserVersionType.

Your application is forbidden from altering the version number set by Hibernate. To artificially increase the version number, see the documentation for properties LockModeType.OPTIMISTIC_FORCE_INCREMENT or LockModeType.PESSIMISTIC_FORCE_INCREMENTcheck in the Hibernate Entity Manager reference documentation.

Database-generated version numbers

If the version number is generated by the database, such as a trigger, use the annotation @org.hibernate.annotations.Generated(GenerationTime.ALWAYS).

Example 8.2. Declaring a version property in hbm.xml


<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
  -->
<version
        column="version_column"
        name="propertyName"
        type="typename"
        access="field|property|ClassName"
        unsaved-value="null|negative|undefined"
        generated="never|always"
        insert="true|false"
        node="element-name|@attribute-name|element/@attribute|."
/>
column

The name of the column holding the version number. Optional, defaults to the property name.

name

The name of a property of the persistent class.

type

The type of the version number. Optional, defaults to integer.

access

Hibernate's strategy for accessing the property value. Optional, defaults to property.

unsaved-value

Indicates that an instance is newly instantiated and thus unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value, undefined, indicates that the identifier property value should be used. Optional.

generated

Indicates that the version property value is generated by the database. Optional, defaults to never.

insert

Whether or not to include the version column in SQL insert statements. Defaults to true, but you can set it to false if the database column is defined with a default value of 0.


Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications for other purposes as well. Timestamping is automatically used if you the @Version annotation on a Date or Calendar.


Hibernate can retrieve the timestamp value from the database or the JVM, by reading the value you specify for the @org.hibernate.annotations.Source annotation. The value can be either org.hibernate.annotations.SourceType.DB or org.hibernate.annotations.SourceType.VM. The default behavior is to use the database, and is also used if you don't specify the annotation at all.

The timestamp can also be generated by the database instead of Hibernate, if you use the @org.hibernate.annotations.Generated(GenerationTime.ALWAYS) annotation.

Example 8.4. The timestamp element in hbm.xml


<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
  ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
  -->
<timestamp
        column="timestamp_column"
        name="propertyName"
        access="field|property|ClassName"
        unsaved-value="null|undefined"
        source="vm|db"
        generated="never|always"
        node="element-name|@attribute-name|element/@attribute|."
/>
column

The name of the column which holds the timestamp. Optional, defaults to the property namel

name

The name of a JavaBeans style property of Java type Date or Timestamp of the persistent class.

access

The strategy Hibernate uses to access the property value. Optional, defaults to property.

unsaved-value

A version property which indicates than instance is newly instantiated, and unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value of undefined indicates that Hibernate uses the identifier property value.

source

Whether Hibernate retrieves the timestamp from the database or the current JVM. Database-based timestamps incur an overhead because Hibernate needs to query the database each time to determine the incremental next value. However, database-derived timestamps are safer to use in a clustered environment. Not all database dialects are known to support the retrieval of the database's current timestamp. Others may also be unsafe for locking, because of lack of precision.

generated

Whether the timestamp property value is generated by the database. Optional, defaults to never.


Typically, you only need to specify an isolation level for the JDBC connections and let the database handle locking issues. If you do need to obtain exclusive pessimistic locks or re-obtain locks at the start of a new transaction, Hibernate gives you the tools you need.

Note

Hibernate always uses the locking mechanism of the database, and never lock objects in memory.

The LockMode class defines the different lock levels that Hibernate can acquire.

LockMode.WRITE

acquired automatically when Hibernate updates or inserts a row.

LockMode.UPGRADE

acquired upon explicit user request using SELECT ... FOR UPDATE on databases which support that syntax.

LockMode.UPGRADE_NOWAIT

acquired upon explicit user request using a SELECT ... FOR UPDATE NOWAIT in Oracle.

LockMode.UPGRADE_SKIPLOCKED

acquired upon explicit user request using a SELECT ... FOR UPDATE SKIP LOCKED in Oracle, or SELECT ... with (rowlock,updlock,readpast) in SQL Server.

LockMode.READ

acquired automatically when Hibernate reads data under Repeatable Read or Serializable isolation level. It can be re-acquired by explicit user request.

LockMode.NONE

The absence of a lock. All objects switch to this lock mode at the end of a Transaction. Objects associated with the session via a call to update() or saveOrUpdate() also start out in this lock mode.

The explicit user request mentioned above occurs as a consequence of any of the following actions:

  • A call to Session.load(), specifying a LockMode.

  • A call to Session.lock().

  • A call to Query.setLockMode().

If you call Session.load() with option UPGRADE, UPGRADE_NOWAIT or UPGRADE_SKIPLOCKED, and the requested object is not already loaded by the session, the object is loaded using SELECT ... FOR UPDATE. If you call load() for an object that is already loaded with a less restrictive lock than the one you request, Hibernate calls lock() for that object.

Session.lock() performs a version number check if the specified lock mode is READ, UPGRADE, UPGRADE_NOWAIT or UPGRADE_SKIPLOCKED. In the case of UPGRADE, UPGRADE_NOWAIT or UPGRADE_SKIPLOCKED, SELECT ... FOR UPDATE syntax is used.

If the requested lock mode is not supported by the database, Hibernate uses an appropriate alternate mode instead of throwing an exception. This ensures that applications are portable.

Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much data, in terms of width (values/columns) and/or depth (results/rows), adds unnecessary overhead in terms of both JDBC communication and ResultSet processing. Fetching too little data causes additional fetches to be needed. Tuning how an application fetches data presents a great opportunity to influence the application's overall performance.

The concept of fetching breaks down into two different questions.

  • When should the data be fetched? Now? Later?

  • How should the data be fetched?

Note

"now" is generally termed eager or immediate. "later" is generally termed lazy or delayed.

There are a number of scopes for defining fetching:

The strategies

SELECT

Performs a separate SQL select to load the data. This can either be EAGER (the second select is issued immediately) or LAZY (the second select is delayed until the data is needed). This is the strategy generally termed N+1.

JOIN

Inherently an EAGER style of fetching. The data to be fetched is obtained through the use of an SQL join.

BATCH

Performs a separate SQL select to load a number of related data items using an IN-restriction as part of the SQL WHERE-clause based on a batch size. Again, this can either be EAGER (the second select is issued immediately) or LAZY (the second select is delayed until the data is needed).

SUBSELECT

Performs a separate SQL select to load associated data based on the SQL restriction used to load the owner. Again, this can either be EAGER (the second select is issued immediately) or LAZY (the second select is delayed until the data is needed).

Let's consider these topics as it relates to an simple domain model and a few use cases.


Important

The Hibernate recommendation is to statically mark all associations lazy and to use dynamic fetching strategies for eagerness. This is unfortunately at odds with the JPA specification which defines that all one-to-one and many-to-one associations should be eagerly fetched by default. Hibernate, as a JPA provider, honors that default.



[2] Except in the case of HQL/JPQL; see xyz

First we need to decide what all to discuss here as that phrase has so many connotations. Do we cover

  • JDBC batch updates?
  • Session w/ incremental flushing?
  • StatelessSession?
  • Java EE batching?
  • Any/all of the above?
  • Others?

JDBC offers support for batching together SQL statements that can be represented as a single PreparedStatement. Implementation wise this generally means that drivers will send the batched operation to the server in one call, which can save on network calls to the database. Hibernate can leverage JDBC batching. The following settings control this behavior.

  • hibernate.jdbc.batch_size - Controls the maximum number of statements Hibernate will batch together before asking the driver to execute the batch. Zero or a negative number disables this feature.

  • hibernate.jdbc.batch_versioned_data - Some JDBC drivers return incorrect row counts when a batch is executed. If your JDBC driver falls into this category this setting should be set to false. Otherwise it is safe to enable this which will allow Hibernate to still batch the DML for versioned entities and still use the returned row counts for optimitic lock checks. Currently defaults to false to be safe.

  • hibernate.jdbc.batch.builder - Names the implementation class used to manage batching capabilities. It is almost never a good idea to switch from Hibernate's default implementation. But if you wish to, this setting would name the org.hibernate.engine.jdbc.batch.spi.BatchBuilder implementation to use.

  • hibernate.order_updates - Forces Hibernate to order SQL updates by the entity type and the primary key value of the items being updated. This allows for more batching to be used. It will also result in fewer transaction deadlocks in highly concurrent systems. Comes with a performance hit, so benchmark before and after to see if this actually helps or hurts your application.

  • hibernate.order_inserts - Forces Hibernate to order inserts to allow for more batching to be used. Comes with a performance hit, so benchmark before and after to see if this actually helps or hurts your application.

Hibernate defines the ability to integrate with pluggable providers for the purpose of caching data outside the context of a particular Session. This section defines the settings which control that behavior.

Besides specific provider configuration, there are a number of configurations options on the Hibernate side of the integration that control various caching behavior:

  • hibernate.cache.use_second_level_cache - Enable or disable second level caching overall. Default is true.

  • hibernate.cache.use_query_cache - Enable or disable second level caching of query results. Default is false.
  • hibernate.cache.query_cache_factory - Query result caching is handled by a special contract that deals with staleness-based invalidation of the results. The default implementation does not allow stale results at all. Use this for applications that would like to relax that. Names an implementation of org.hibernate.cache.spi.QueryCacheFactory
  • hibernate.cache.use_minimal_puts - Optimizes second-level cache operations to minimize writes, at the cost of more frequent reads. Providers typically set this appropriately.
  • hibernate.cache.region_prefix - Defines a name to be used as a prefix to all second-level cache region names.
  • hibernate.cache.default_cache_concurrency_strategy - In Hibernate second-level caching, all regions can be configured differently including the concurrency strategy to use when accessing the region. This setting allows to define a default strategy to be used. This setting is very rarely required as the pluggable providers do specify the default strategy to use. Valid values include: read-only, read-write, nonstrict-read-write, transactional.
  • hibernate.cache.use_structured_entries - If true, forces Hibernate to store data in the second-level cache in a more human-friendly format. Can be useful if you'd like to be able to "browse" the data directly in your cache, but does have a performance impact.
  • hibernate.cache.auto_evict_collection_cache - Enables or disables the automatic eviction of a bi-directional association's collection cache entry when the association is changed just from the owning side. This is disabled by default, as it has a performance impact to track this state. However if your application does not manage both sides of bi-directional association where the collection side is cached, the alternative is to have stale data in that collection cache.

It is useful for the application to react to certain events that occur inside Hibernate. This allows for the implementation of generic functionality and the extension of Hibernate functionality.

If you have to react to particular events in the persistence layer, you can also use the Hibernate event architecture. The event system can be used in place of or in addition to interceptors.

Many methods of the Session interface correlate to an event type. The full range of defined event types is declared as enum values on org.hibernate.event.spi.EventType. When a request is made of one of these methods, the Session generates an appropriate event and passes it to the configured event listener(s) for that type. Applications are free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implementation of the LoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.

Note

See ??? for information on registering custom event listeners.

The listeners should be considered stateless; they are shared between requests, and should not save any state as instance variables.

A custom listener implements the appropriate interface for the event it wants to process and/or extend one of the convenience base classes (or even the default event listeners used by Hibernate out-of-the-box as these are declared non-final for this purpose). Here is an example of a custom load event listener:


Usually, declarative security in Hibernate applications is managed in a session facade layer. Hibernate allows certain actions to be permissioned via JACC, and authorized via JAAS. This is an optional functionality that is built on top of the event architecture.

First, you must configure the appropriate event listeners, to enable the use of JACC authorization. Again, see ??? for the details. Below is an example of an appropriate org.hibernate.integrator.spi.Integrator implementation for this purpose.

Example 12.2. JACC listener registration example

import org.hibernate.event.service.spi.DuplicationStrategy;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.secure.internal.JACCPreDeleteEventListener;
import org.hibernate.secure.internal.JACCPreInsertEventListener;
import org.hibernate.secure.internal.JACCPreLoadEventListener;
import org.hibernate.secure.internal.JACCPreUpdateEventListener;
import org.hibernate.secure.internal.JACCSecurityListener;

public class JaccEventListenerIntegrator implements Integrator {

	private static final DuplicationStrategy JACC_DUPLICATION_STRATEGY = new DuplicationStrategy() {
		@Override
		public boolean areMatch(Object listener, Object original) {
			return listener.getClass().equals( original.getClass() ) &&
					JACCSecurityListener.class.isInstance( original );
		}

		@Override
		public Action getAction() {
			return Action.KEEP_ORIGINAL;
		}
	};

	@Override
	@SuppressWarnings( {"unchecked"})
	public void integrate(
			Configuration configuration,
			SessionFactoryImplementor sessionFactory,
			SessionFactoryServiceRegistry serviceRegistry) {
		boolean isSecurityEnabled = configuration.getProperties().containsKey( AvailableSettings.JACC_ENABLED );
		if ( !isSecurityEnabled ) {
			return;
		}

		final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
		eventListenerRegistry.addDuplicationStrategy( JACC_DUPLICATION_STRATEGY );

		final String jaccContextId = configuration.getProperty( Environment.JACC_CONTEXTID );
		eventListenerRegistry.prependListeners( EventType.PRE_DELETE, new JACCPreDeleteEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_INSERT, new JACCPreInsertEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_UPDATE, new JACCPreUpdateEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_LOAD, new JACCPreLoadEventListener(jaccContextId) );
	}
}

You must also decide how to configure your JACC provider. Consult your JACC provider documentation.

JPA also defines a more limited set of callbacks through annotations.


There are 2 available approaches defined for specifying callback handling:

  • The first approach is to annotate methods on the entity itself to receive notification of particular entity life cycle event(s).

  • The second is to use a separate entity listener class. An entity listener is a stateless class with a no-arg constructor. The callback annotations are placed on a method of this class instead of the entity class. The entity listener class is then associated with the entity using the javax.persistence.EntityListeners annotation


These approaches can be mixed, meaning you can use both together.

Regardless of whether the callback method is defined on the entity or on an entity listener, it must have a void-return signature. The name of the method is irrelevant as it is the placement of the callback annotations that makes the method a callback. In the case of callback methods defined on the entity class, the method must additionally have a no-argument signature. For callback methods defined on an entity listener class, the method must have a single argument signature; the type of that argument can be either java.lang.Object (to facilitate attachment to multiple entities) or the specific entity type.

A callback method can throw a RuntimeException. If the callback method does throw a RuntimeException, then the current transaction, if any, must be rolled back.

A callback method must not invoke EntityManager or Query methods!

It is possible that multiple callback methods are defined for a particular lifecycle event. When that is the case, the defined order of execution is well defined by the JPA spec (specifically section 3.5.4):

  • Any default listeners associated with the entity are invoked first, in the order they were specified in the XML. See the javax.persistence.ExcludeDefaultListeners annotation.

  • Next, entity listener class callbacks associated with the entity hierarchy are invoked, in the order they are defined in the EntityListeners. If multiple classes in the entity hierarchy define entity listeners, the listeners defined for a superclass are invoked before the listeners defined for its subclasses. See the javax.persistence.ExcludeSuperclassListeners annotation.

  • Lastly, callback methods defined on the entity hierarchy are invoked. If a callback type is annotated on both an entity and one or more of its superclasses without method overriding, both would be called, the most general superclass first. An entity class is also allowed to override a callback method defined in a superclass in which case the super callback would not get invoked; the overriding method would get invoked provided it is annotated.

The Hibernate Query Language (HQL) and Java Persistence Query Language (JPQL) are both object model focused query languages similar in nature to SQL. JPQL is a heavily-inspired-by subset of HQL. A JPQL query is always a valid HQL query, the reverse is not true however.

Both HQL and JPQL are non-type-safe ways to perform query operations. Criteria queries offer a type-safe approach to querying. See Chapter 14, Criteria for more information.

Both HQL and JPQL allow SELECT, UPDATE and DELETE statements to be performed. HQL additionally allows INSERT statements, in a form similar to a SQL INSERT-SELECT.

Important

Care should be taken as to when a UPDATE or DELETE statement is executed.

 

Caution should be used when executing bulk update or delete operations because they may result in inconsistencies between the database and the entities in the active persistence context. In general, bulk update and delete operations should only be performed within a transaction in a new persistence con- text or before fetching or accessing entities whose state might be affected by such operations.

 
 --Section 4.10 of the JPA 2.0 Specification

The BNF for UPDATE statements is the same in HQL and JPQL:

update_statement ::= update_clause [where_clause]

update_clause ::= UPDATE entity_name [[AS] identification_variable]
        SET update_item {, update_item}*

update_item ::= [identification_variable.]{state_field | single_valued_object_field}
        = new_value

new_value ::= scalar_expression |
                simple_entity_expression |
                NULL

UPDATE statements, by default, do not effect the version or the timestamp attribute values for the affected entities. However, you can force Hibernate to set the version or timestamp attribute values through the use of a versioned update. This is achieved by adding the VERSIONED keyword after the UPDATE keyword. Note, however, that this is a Hibernate specific feature and will not work in a portable manner. Custom version types, org.hibernate.usertype.UserVersionType, are not allowed in conjunction with a update versioned statement.

An UPDATE statement is executed using the executeUpdate of either org.hibernate.Query or javax.persistence.Query. The method is named for those familiar with the JDBC executeUpdate on java.sql.PreparedStatement. The int value returned by the executeUpdate() method indicates the number of entities effected by the operation. This may or may not correlate to the number of rows effected in the database. An HQL 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. Using a JOINED inheritance hierarchy, a delete against one of the subclasses may actually result in deletes against not just the table to which that subclass is mapped, but also the "root" table and tables in between


Important

Neither UPDATE nor DELETE statements are allowed to result in what is called an implicit join. Their form already disallows explicit joins.

HQL adds the ability to define INSERT statements as well. There is no JPQL equivalent to this. The BNF for an HQL INSERT statement is:

insert_statement ::= insert_clause select_statement

insert_clause ::= INSERT INTO entity_name (attribute_list)

attribute_list ::= state_field[, state_field ]*

The attribute_list is analogous to the column specification in the SQL INSERT statement. For entities involved in mapped inheritance, only attributes directly defined on the named entity can be used in the attribute_list. Superclass properties are not allowed and subclass properties do not make sense. In other words, INSERT statements are inherently non-polymorphic.

select_statement can be any valid HQL select query, with the caveat that the return types must match the types expected by the insert. Currently, this is checked during query compilation rather than allowing the check to relegate to the database. This may cause problems between Hibernate Types which are equivalent as opposed to equal. For example, this might cause lead to issues with mismatches between an attribute mapped as a org.hibernate.type.DateType and an attribute defined as a org.hibernate.type.TimestampType, even though the database might not make a distinction or might be able to handle the conversion.

For the id attribute, the insert statement gives you two options. You can either explicitly specify the id property in the attribute_list, in which case its value is taken from the corresponding select expression, or omit it from the attribute_list in which case a generated value is used. This latter option is only available when using id generators that operate in the database; attempting to use this option with any in memory type generators will cause an exception during parsing.

For optimistic locking attributes, the insert statement again gives you two options. You can either specify the attribute in the attribute_list in which case its value is taken from the corresponding select expressions, or omit it from the attribute_list in which case the seed value defined by the corresponding org.hibernate.type.VersionType is used.


The FROM clause is responsible defining the scope of object model types available to the rest of the query. It also is responsible for defining all the identification variables available to the rest of the query.

A root entity reference, or what JPA calls a range variable declaration, is specifically a reference to a mapped entity type from the application. It cannot name component/ embeddable types. And associations, including collections, are handled in a different manner discussed later.

The BNF for a root entity reference is:

root_entity_reference ::= entity_name [AS] identification_variable

We see that the query is defining a root entity reference to the com.acme.Cat object model type. Additionally, it declares an alias of c to that com.acme.Cat reference; this is the identification variable.

Usually the root entity reference just names the entity name rather than the entity class FQN. By default the entity name is the unqualified entity class name, here Cat


Multiple root entity references can also be specified. Even naming the same entity!


The FROM clause can also contain explicit relationship joins using the join keyword. These joins can be either inner or left outer style joins.



An important use case for explicit joins is to define FETCH JOINS which override the laziness of the joined association. As an example, given an entity named Customer with a collection-valued association named orders


As you can see from the example, a fetch join is specified by injecting the keyword fetch after the keyword join. In the example, we used a left outer join because we want to return customers who have no orders also. Inner joins can also be fetched. But inner joins still filter. In the example, using an inner join instead would have resulted in customers without any orders being filtered out of the result.

Important

Fetch joins are not valid in sub-queries.

Care should be taken when fetch joining a collection-valued association which is in any way further restricted; the fetched collection will be restricted too! For this reason it is usually considered best practice to not assign an identification variable to fetched joins except for the purpose of specifying nested fetch joins.

Fetch joins should not be used in paged queries (aka, setFirstResult/ setMaxResults). Nor should they be used with the HQL scroll or iterate features.

HQL also defines a WITH clause to qualify the join conditions. Again, this is specific to HQL; JPQL does not define this feature.


The important distinction is that in the generated SQL the conditions of the with clause are made part of the on clause in the generated SQL as opposed to the other queries in this section where the HQL/JPQL conditions are made part of the where clause in the generated SQL. The distinction in this specific example is probably not that significant. The with clause is sometimes necessary in more complicated queries.

Explicit joins may reference association or component/embedded attributes. For further information about collection-valued association references, see Section 13.3.5, “Collection member references”. In the case of component/embedded attributes, the join is simply logical and does not correlate to a physical (SQL) join.

Another means of adding to the scope of object model types available to the query is through the use of implicit joins, or path expressions.


An implicit join always starts from an identification variable, followed by the navigation operator (.), followed by an attribute for the object model type referenced by the initial identification variable. In the example, the initial identification variable is c which refers to the Customer entity. The c.chiefExecutive reference then refers to the chiefExecutive attribute of the Customer entity. chiefExecutive is an association type so we further navigate to its age attribute.

Important

If the attribute represents an entity association (non-collection) or a component/embedded, that reference can be further navigated. Basic values and collection-valued associations cannot be further navigated.

As shown in the example, implicit joins can appear outside the FROM clause. However, they affect the FROM clause. Implicit joins are always treated as inner joins. Multiple references to the same implicit join always refer to the same logical and physical (SQL) join.


Just as with explicit joins, implicit joins may reference association or component/embedded attributes. For further information about collection-valued association references, see Section 13.3.5, “Collection member references”. In the case of component/embedded attributes, the join is simply logical and does not correlate to a physical (SQL) join. Unlike explicit joins, however, implicit joins may also reference basic state fields as long as the path expression ends there.

References to collection-valued associations actually refer to the values of that collection.


In the example, the identification variable o actually refers to the object model type Order which is the type of the elements of the Customer#orders association.

The example also shows the alternate syntax for specifying collection association joins using the IN syntax. Both forms are equivalent. Which form an application chooses to use is simply a matter of taste.

We said earlier that collection-valued associations actually refer to the values of that collection. Based on the type of collection, there are also available a set of explicit qualification expressions.


VALUE

Refers to the collection value. Same as not specifying a qualifier. Useful to explicitly show intent. Valid for any type of collection-valued reference.

INDEX

According to HQL rules, this is valid for both Maps and Lists which specify a javax.persistence.OrderColumn annotation to refer to the Map key or the List position (aka the OrderColumn value). JPQL however, reserves this for use in the List case and adds KEY for the MAP case. Applications interested in JPA provider portability should be aware of this distinction.

KEY

Valid only for Maps. Refers to the map's key. If the key is itself an entity, can be further navigated.

ENTRY

Only valid only for Maps. Refers to the Map's logical java.util.Map.Entry tuple (the combination of its key and value). ENTRY is only valid as a terminal path and only valid in the select clause.

See Section 13.4.9, “Collection-related expressions” for additional details on collection related expressions.

Essentially expressions are references that resolve to basic or tuple values.

String literals are enclosed in single-quotes. To escape a single-quote within a string literal, use double single-quotes.


Numeric literals are allowed in a few different forms.


In the scientific notation form, the E is case insensitive.

Specific typing can be achieved through the use of the same suffix approach specified by Java. So, L denotes a long; D denotes a double; F denotes a float. The actual suffix is case insensitive.

The boolean literals are TRUE and FALSE, again case-insensitive.

Enums can even be referenced as literals. The fully-qualified enum class name must be used. HQL can also handle constants in the same manner, though JPQL does not define that as supported.

Entity names can also be used as literal. See Section 13.4.10, “Entity type”.

Date/time literals can be specified using the JDBC escape syntax: {d 'yyyy-mm-dd'} for dates, {t 'hh:mm:ss'} for times and {ts 'yyyy-mm-dd hh:mm:ss[.millis]'} (millis optional) for timestamps. These literals only work if you JDBC drivers supports them.

HQL supports all 3 of the following forms. JPQL does not support the HQL-specific positional parameters notion. It is good practice to not mix forms in a given query.

Both HQL and JPQL define some standard functions that are available regardless of the underlying database in use. HQL can also understand additional functions defined by the Dialect as well as the application.

There are a few specialized expressions for working with collection-valued associations. Generally these are just abbreviated forms or other expressions for the sake of conciseness.

SIZE

Calculate the size of a collection. Equates to a subquery!

MAXELEMENT

Available for use on collections of basic type. Refers to the maximum value as determined by applying the max SQL aggregation.

MAXINDEX

Available for use on indexed collections. Refers to the maximum index (key/position) as determined by applying the max SQL aggregation.

MINELEMENT

Available for use on collections of basic type. Refers to the minimum value as determined by applying the min SQL aggregation.

MININDEX

Available for use on indexed collections. Refers to the minimum index (key/position) as determined by applying the min SQL aggregation.

ELEMENTS

Used to refer to the elements of a collection as a whole. Only allowed in the where clause. Often used in conjunction with ALL, ANY or SOME restrictions.

INDICES

Similar to elements except that indices refers to the collections indices (keys/positions) as a whole.


Elements of indexed collections (arrays, lists, and maps) can be referred to by index operator.


See also Section 13.3.5.1, “Special case - qualified path expressions” as there is a good deal of overlap.

Both the simple and searched forms are supported, as well as the 2 SQL defined abbreviated forms (NULLIF and COALESCE)

The SELECT clause identifies which objects and values to return as the query results. The expressions discussed in Section 13.4, “Expressions” are all valid select expressions, except where otherwise noted. See the section Section 13.10, “Query API” for information on handling the results depending on the types of values specified in the SELECT clause.

There is a particular expression type that is only valid in the select clause. Hibernate calls this dynamic instantiation. JPQL supports some of that feature and calls it a constructor expression


So rather than dealing with the Object[] (again, see Section 13.10, “Query API”) here we are wrapping the values in a type-safe java object that will be returned as the results of the query. The class reference must be fully qualified and it must have a matching constructor.

The class here need not be mapped. If it does represent an entity, the resulting instances are returned in the NEW state (not managed!).

That is the part JPQL supports as well. HQL supports additional dynamic instantiation features. First, the query can specify to return a List rather than an Object[] for scalar results:


The results from this query will be a List<List> as opposed to a List<Object[]>

HQL also supports wrapping the scalar results in a Map.


The results from this query will be a List<Map<String,Object>> as opposed to a List<Object[]>. The keys of the map are defined by the aliases given to the select expressions.

Predicates form the basis of the where clause, the having clause and searched case expressions. They are expressions which resolve to a truth value, generally TRUE or FALSE, although boolean comparisons involving NULLs generally resolve to UNKNOWN.

Comparisons involve one of the comparison operators - =, >, >=, <, <=, <>]>. HQL also defines <![CDATA[!= as a comparison operator synonymous with <>. The operands should be of the same type.


Comparisons can also involve subquery qualifiers - ALL, ANY, SOME. SOME and ANY are synonymous.

The ALL qualifier resolves to true if the comparison is true for all of the values in the result of the subquery. It resolves to false if the subquery result is empty.


The ANY/SOME qualifier resolves to true if the comparison is true for some of (at least one of) the values in the result of the subquery. It resolves to false if the subquery result is empty.

IN predicates performs a check that a particular value is in a list of values. Its syntax is:

in_expression ::= single_valued_expression
            [NOT] IN single_valued_list

single_valued_list ::= constructor_expression |
            (subquery) |
            collection_valued_input_parameter

constructor_expression ::= (expression[, expression]*)

The types of the single_valued_expression and the individual values in the single_valued_list must be consistent. JPQL limits the valid types here to string, numeric, date, time, timestamp, and enum types. In JPQL, single_valued_expression can only refer to:

In HQL, single_valued_expression can refer to a far more broad set of expression types. Single-valued association are allowed. So are component/embedded attributes, although that feature depends on the level of support for tuple or row value constructor syntax in the underlying database. Additionally, HQL does not limit the value type in any way, though application developers should be aware that different types may incur limited support based on the underlying database vendor. This is largely the reason for the JPQL limitations.

The list of values can come from a number of different sources. In the constructor_expression and collection_valued_input_parameter, the list of values must not be empty; it must contain at least one value.


In Hibernate the HQL/JPQL query is represented as org.hibernate.Query which is obtained from the Session. If the HQL/JPQL is a named query, Session#getNamedQuery would be used; otherwise Session#createQuery would be used.


The Query interface can then be used to control the execution of the query. For example, we may want to specify an execution timeout or control caching.


For complete details, see the Query javadocs.

Important

Query hints here are database query hints. They are added directly to the generated SQL according to Dialect#getQueryHintString. The JPA notion of query hints, on the other hand, refer to hints that target the provider (Hibernate). So even though they are called the same, be aware they have a very different purpose. Also be aware that Hibernate query hints generally make the application non-portable across databases unless the code adding them first checks the Dialect.

Flushing is covered in detail in ???. Locking is covered in detail in ???. The concept of read-only state is covered in Chapter 4, Persistence Contexts.

Hibernate also allows an application to hook into the process of building the query results via the org.hibernate.transform.ResultTransformer contract. See its javadocs as well as the Hibernate-provided implementations for additional details.

The last thing that needs to happen before we can execute the query is to bind the values for any parameters defined in the query. Query defines many overloaded methods for this purpose. The most generic form takes the value as well as the Hibernate Type.


Hibernate generally understands the expected type of the parameter given its context in the query. In the previous example, since we are using the parameter in a LIKE comparison against a String-typed attribute Hibernate would automatically infer the type; so the above could be simplified.


There are also short hand forms for binding common types such as strings, booleans, integers, etc.


In terms of execution, Hibernate offers 4 different methods. The 2 most commonly used are

  • Query#list - executes the select query and returns back the list of results.

  • Query#uniqueResult - executes the select query and returns the single result. If there were more than one result an exception is thrown.


Note

If the unique result is used often and the attributes upon which it is based are unique, you may want to consider mapping a natural-id and using the natural-id loading API. See the Hibernate Domain Mapping Guide for more information on natural-ids.

Hibernate offers 2 additional, specialized methods for performing the query and handling results. Query#scroll works in tandem with the JDBC notion of a scrollable ResultSet. The scroll method is overloaded. Then main form accepts a single argument of type org.hibernate.ScrollMode which indicates the type of scrolling to be used. See the javadocs for ScrollMode for the details on each. The second form accepts no argument and will use the ScrollMode indicated by Dialect#defaultScrollMode. Query#scroll returns a org.hibernate.ScrollableResults which wraps the underlying JDBC (scrollable) ResultSet and provides access to the results. Since this form holds the JDBC ResultSet open, the application should indicate when it is done with the ScrollableResults by calling its close method (as inherited from java.io.Closeable, so that ScrollableResults will work with try-with-resources blocks!). If left unclosed by the application, Hibernate will automatically close the ScrollableResults when the current transaction completes.

Note

If you plan to use Query#scroll with collection fetches it is important that your query explicitly order the results so that the JDBC results contain the the related rows sequentially.

The last is Query#iterate, which is intended for loading entities which the the application feels certain will be in the second-level cache. The idea behind iterate is that just the matching identifiers will be obtained in the SQL query. From these the identifiers are resolved by second-level cache lookup. If these second-level cache lookups fail, additional queries will need to be issued against the database. This operation can perform significantly better for loading large numbers of entities that for certain already exist in the second-level cache. In cases where many of the entities do not exist in the second-level cache, this operation will almost definitely perform worse. The Iterator returned from Query#iterate is actually a specially typed Iterator: org.hibernate.engine.HibernateIterator. It is specialized to expose a close method (again, inherited from java.io.Closeable). When you are done with this Iterator you should close it, either by casting to HibernateIterator or Closeable, or by calling org.hibernate.Hibernate#close

In JPA the query is represented by javax.persistence.Query or javax.persistence.TypedQuery as obtained from the EntityManager. For named queries EntityManager#createNamedQuery is used; otherwise EntityManager#createQuery is used.


Note

This will all sound very familiar. Not only was the JPQL syntax heavily inspired by HQL, but many of the JPA APIs were heavily inspired by Hibernate. The 2 Query contracts are very similar.

The Query interface can then be used to control the execution of the query. For example, we may want to specify an execution timeout or control caching.


For complete details, see the Query javadocs. Many of the settings controlling the execution of the query are defined as hints. JPA defines some standard hints (like timeout in the example), but most are provider specific. Relying on provider specific hints limits your applications portability to some degree.

JPA standardized Query hints

Hibernate specific JPA Query hints

  • org.hibernate.cacheMode - Defines the CacheMode to use. See org.hibernate.Query#setCacheMode.

  • org.hibernate.cacheable - Defines whether the query is cacheable. true/false. See org.hibernate.Query#setCacheable.

  • org.hibernate.cacheRegion For queries that are cacheable, defines a specific cache region to use. See org.hibernate.Query#setCacheRegion.

  • org.hibernate.comment - Defines the comment to apply to the generated SQL. See org.hibernate.Query#setComment.

  • org.hibernate.fetchSize - Defines the JDBC fetch-size to use. See org.hibernate.Query#setFetchSize

  • org.hibernate.flushMode - Defines the Hibernate-specific FlushMode to use. See org.hibernate.Query#setFlushMode. If possible, prefer using javax.persistence.Query#setFlushMode instead.

  • org.hibernate.readOnly - Defines that entities and collections loaded by this query should be marked as read-only. See org.hibernate.Query#setReadOnly

Just as seen in the Hibernate API, the final thing that needs to happen before the query can be executed is to bind the values for any defined parameters. JPA defines a simplified set of parameter binding methods. Essentially it supports setting the parameter value (by name/position) and a specialized form for Calendar/Date types additionally accepting a TemporalType.


Additionally, JPA allows access to read some information about parameters as well.

As far as execution, JPA supports the two main methods discussed above for the Hibernate API. It calls these methods Query#getResultList and Query#getSingleResult. They behave exactly as described for org.hibernate.Query#list and org.hibernate.Query#uniqueResult.

Criteria queries offer a type-safe alternative to HQL, JPQL and native-sql queries.

Important

Hibernate offers an older, legacy org.hibernate.Criteria API which should be considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery. For details on the org.hibernate.Criteria API, see Appendix B, Legacy Hibernate Criteria Queries.

This chapter will focus on the JPA APIs for declaring type-safe criteria queries.

Criteria queries are a programmatic, type-safe way to express a query. They are type-safe in terms of using interfaces and classes to represent various structural parts of a query such as the query itself, or the select clause, or an order-by, etc. They can also be type-safe in terms of referencing attributes as we will see in a bit. Users of the older Hibernate org.hibernate.Criteria query API will recognize the general approach, though we believe the JPA API to be superior as it represents a clean look at the lessons learned from that API.

Criteria queries are essentially an object graph, where each part of the graph represents an increasing (as we navigate down this graph) more atomic part of query. The first step in performing a criteria query is building this graph. The javax.persistence.criteria.CriteriaBuilder interface is the first thing with which you need to become acquainted to begin using criteria queries. Its role is that of a factory for all the individual pieces of the criteria. You obtain a javax.persistence.criteria.CriteriaBuilder instance by calling the getCriteriaBuilder method of either javax.persistence.EntityManagerFactory or javax.persistence.EntityManager.

The next step is to obtain a javax.persistence.criteria.CriteriaQuery. This is accomplished using one of the 3 methods on javax.persistence.criteria.CriteriaBuilder for this purpose:

<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
CriteriaQuery<Tuple> createTupleQuery();
CriteriaQuery<Object> createQuery();

Each serves a different purpose depending on the expected type of the query results.

Note

Chapter 6 Criteria API of the JPA Specification already contains a decent amount of reference material pertaining to the various parts of a criteria query. So rather than duplicate all that content here, lets instead look at some of the more widely anticipated usages of the API.

The type of the criteria query (aka the <T>) indicates the expected types in the query result. This might be an entity, an Integer, or any other object.

There are actually a few different ways to select multiple values using criteria queries. We will explore 2 options here, but an alternative recommended approach is to use tuples as described in Section 14.2, “Tuple criteria queries”. Or consider a wrapper query; see Section 14.1.4, “Selecting a wrapper” for details.


Technically this is classified as a typed query, but you can see from handling the results that this is sort of misleading. Anyway, the expected result type here is an array.

The example then uses the array method of javax.persistence.criteria.CriteriaBuilder which explicitly combines individual selections into a javax.persistence.criteria.CompoundSelection.


Just as we saw in Example 14.3, “Selecting an array” we have a typed criteria query returning an Object array. Both queries are functionally equivalent. This second example uses the multiselect method which behaves slightly differently based on the type given when the criteria query was first built, but in this case it says to select and return an Object[].

Another alternative to Section 14.1.3, “Selecting multiple values” is to instead select an object that will wrap the multiple values. Going back to the example query there, rather than returning an array of [Person#id, Person#age] instead declare a class that holds these values and instead return that.


First we see the simple definition of the wrapper object we will be using to wrap our result values. Specifically notice the constructor and its argument types. Since we will be returning PersonWrapper objects, we use PersonWrapper as the type of our criteria query.

This example illustrates the use of the javax.persistence.criteria.CriteriaBuilder method construct which is used to build a wrapper expression. For every row in the result we are saying we would like a PersonWrapper instantiated with the remaining arguments by the matching constructor. This wrapper expression is then passed as the select.

A better approach to Section 14.1.3, “Selecting multiple values” is to use either a wrapper (which we just saw in Section 14.1.4, “Selecting a wrapper”) or using the javax.persistence.Tuple contract.


This example illustrates accessing the query results through the javax.persistence.Tuple interface. The example uses the explicit createTupleQuery of javax.persistence.criteria.CriteriaBuilder. An alternate approach is to use createQuery passing Tuple.class.

Again we see the use of the multiselect method, just like in Example 14.4, “Selecting an array (2)”. The difference here is that the type of the javax.persistence.criteria.CriteriaQuery was defined as javax.persistence.Tuple so the compound selections in this case are interpreted to be the tuple elements.

The javax.persistence.Tuple contract provides 3 forms of access to the underlying elements:

typed

The Example 14.6, “Selecting a tuple” example illustrates this form of access in the tuple.get( idPath ) and tuple.get( agePath ) calls. This allows typed access to the underlying tuple values based on the javax.persistence.TupleElement expressions used to build the criteria.

positional

Allows access to the underlying tuple values based on the position. The simple Object get(int position) form is very similar to the access illustrated in Example 14.3, “Selecting an array” and Example 14.4, “Selecting an array (2)”. The <X> X get(int position, Class<X> type form allows typed positional access, but based on the explicitly supplied type which the tuple value must be type-assignable to.

aliased

Allows access to the underlying tuple values based an (optionally) assigned alias. The example query did not apply an alias. An alias would be applied via the alias method on javax.persistence.criteria.Selection. Just like positional access, there is both a typed (Object get(String alias)) and an untyped (<X> X get(String alias, Class<X> type form.

 

A CriteriaQuery object defines a query over one or more entity, embeddable, or basic abstract schema types. The root objects of the query are entities, from which the other types are reached by navigation.

 
 --JPA Specification, section 6.5.2 Query Roots, pg 262

Note

All the individual parts of the FROM clause (roots, joins, paths) implement the javax.persistence.criteria.From interface.

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/JPA. Hibernate also allows you to specify handwritten SQL (including stored procedures) for all create, update, delete, and load operations.

Execution of native SQL queries is controlled via the SQLQuery interface, which is obtained by calling Session.createSQLQuery(). The following sections describe how to use this API for querying.

The most basic SQL query is to get a list of scalars (values).

sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();

These will return a List of Object arrays (Object[]) with scalar values for each column in the CATS table. Hibernate will use ResultSetMetadata to deduce the actual order and types of the returned scalar values.

To avoid the overhead of using ResultSetMetadata, or simply to be more explicit in what is returned, one can use addScalar():

sess.createSQLQuery("SELECT * FROM CATS")
 .addScalar("ID", Hibernate.LONG)
 .addScalar("NAME", Hibernate.STRING)
 .addScalar("BIRTHDATE", Hibernate.DATE)

This query specified:

  • the SQL query string

  • the columns and types to return

This will return Object arrays, but now it will not use ResultSetMetadata but will instead explicitly get the ID, NAME and BIRTHDATE column as respectively a Long, String and a Short from the underlying resultset. This also means that only these three columns will be returned, even though the query is using * and could return more than the three listed columns.

It is possible to leave out the type information for all or some of the scalars.

sess.createSQLQuery("SELECT * FROM CATS")
 .addScalar("ID", Hibernate.LONG)
 .addScalar("NAME")
 .addScalar("BIRTHDATE")

This is essentially the same query as before, but now ResultSetMetaData is used to determine the type of NAME and BIRTHDATE, where as the type of ID is explicitly specified.

How the java.sql.Types returned from ResultSetMetaData is mapped to Hibernate types is controlled by the Dialect. If a specific type is not mapped, or does not result in the expected type, it is possible to customize it via calls to registerHibernateType in the Dialect.

Until now, the result set column names are assumed to be the same as the column names specified in the mapping document. This can be problematic for SQL queries that join multiple tables, since the same column names can appear in more than one table.

Column alias injection is needed in the following query (which most likely will fail):

sess.createSQLQuery("SELECT c.*, m.*  FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
 .addEntity("cat", Cat.class)
 .addEntity("mother", Cat.class)

The query was intended to return two Cat instances per row: a cat and its mother. The query will, however, fail because there is a conflict of names; the instances are mapped to the same column names. Also, on some databases the returned column aliases will most likely be on the form "c.ID", "c.NAME", etc. which are not equal to the columns specified in the mappings ("ID" and "NAME").

The following form is not vulnerable to column name duplication:

sess.createSQLQuery("SELECT {cat.*}, {m.*}  FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID")
 .addEntity("cat", Cat.class)
 .addEntity("mother", Cat.class)

This query specified:

  • the SQL query string, with placeholders for Hibernate to inject column aliases

  • the entities returned by the query

The {cat.*} and {mother.*} notation used above is a shorthand for "all properties". Alternatively, you can list the columns explicitly, but even in this case Hibernate injects the SQL column aliases for each property. The placeholder for a column alias is just the property name qualified by the table alias. In the following example, you retrieve Cats and their mothers from a different table (cat_log) to the one declared in the mapping metadata. You can even use the property aliases in the where clause.

String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
         "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
         "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";

List loggedCats = sess.createSQLQuery(sql)
        .addEntity("cat", Cat.class)
        .addEntity("mother", Cat.class).list()

Named SQL queries can also be defined in the mapping document and called in exactly the same way as a named HQL query. In this case, you do not need to call addEntity().



The <return-join> element is use to join associations and the <load-collection> element is used to define queries which initialize collections,


A named SQL query may return a scalar value. You must declare the column alias and Hibernate type using the <return-scalar> element:


You can externalize the resultset mapping information in a <resultset> element which will allow you to either reuse them across several named queries or through the setResultSetMapping() API.


You can, alternatively, use the resultset mapping information in your hbm files directly in java code.


So far we have only looked at externalizing SQL queries using Hibernate mapping files. The same concept is also available with anntations and is called named native queries. You can use @NamedNativeQuery (@NamedNativeQueries) in conjunction with @SqlResultSetMapping (@SqlResultSetMappings). Like @NamedQuery, @NamedNativeQuery and @SqlResultSetMapping can be defined at class level, but their scope is global to the application. Lets look at a view examples.

Example 15.7, “Named SQL query using @NamedNativeQuery together with @SqlResultSetMapping shows how a resultSetMapping parameter is defined in @NamedNativeQuery. It represents the name of a defined @SqlResultSetMapping. The resultset mapping declares the entities retrieved by this native query. Each field of the entity is bound to an SQL alias (or column name). All fields of the entity including the ones of subclasses and the foreign key columns of related entities have to be present in the SQL query. Field definitions are optional provided that they map to the same column name as the one declared on the class property. In the example 2 entities, Night and Area, are returned and each property is declared and associated to a column name, actually the column name retrieved by the query.

In Example 15.8, “Implicit result set mapping” the result set mapping is implicit. We only describe the entity class of the result set mapping. The property / column mappings is done using the entity mapping values. In this case the model property is bound to the model_txt column.

Finally, if the association to a related entity involve a composite primary key, a @FieldResult element should be used for each foreign key column. The @FieldResult name is composed of the property name for the relationship, followed by a dot ("."), followed by the name or the field or property of the primary key. This can be seen in Example 15.9, “Using dot notation in @FieldResult for specifying associations ”.



Example 15.9. Using dot notation in @FieldResult for specifying associations

@Entity

@SqlResultSetMapping(name="compositekey",
        entities=@EntityResult(entityClass=SpaceShip.class,
            fields = {
                    @FieldResult(name="name", column = "name"),
                    @FieldResult(name="model", column = "model"),
                    @FieldResult(name="speed", column = "speed"),
                    @FieldResult(name="captain.firstname", column = "firstn"),
                    @FieldResult(name="captain.lastname", column = "lastn"),
                    @FieldResult(name="dimensions.length", column = "length"),
                    @FieldResult(name="dimensions.width", column = "width")
                    }),
        columns = { @ColumnResult(name = "surface"),
                    @ColumnResult(name = "volume") } )
@NamedNativeQuery(name="compositekey",
    query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip",
    resultSetMapping="compositekey")
} )
public class SpaceShip {
    private String name;
    private String model;
    private double speed;
    private Captain captain;
    private Dimensions dimensions;
    @Id
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumns( {
            @JoinColumn(name="fname", referencedColumnName = "firstname"),
            @JoinColumn(name="lname", referencedColumnName = "lastname")
            } )
    public Captain getCaptain() {
        return captain;
    }
    public void setCaptain(Captain captain) {
        this.captain = captain;
    }
    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }
    public double getSpeed() {
        return speed;
    }
    public void setSpeed(double speed) {
        this.speed = speed;
    }
    public Dimensions getDimensions() {
        return dimensions;
    }
    public void setDimensions(Dimensions dimensions) {
        this.dimensions = dimensions;
    }
}
@Entity
@IdClass(Identity.class)
public class Captain implements Serializable {
    private String firstname;
    private String lastname;
    @Id
    public String getFirstname() {
        return firstname;
    }
    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
    @Id
    public String getLastname() {
        return lastname;
    }
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
}

Tip

If you retrieve a single entity using the default mapping, you can specify the resultClass attribute instead of resultSetMapping:

@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultClass=SpaceShip.class)

public class SpaceShip {

In some of your native queries, you'll have to return scalar values, for example when building report queries. You can map them in the @SqlResultsetMapping through @ColumnResult. You actually can even mix, entities and scalar returns in the same native query (this is probably not that common though).


An other query hint specific to native queries has been introduced: org.hibernate.callable which can be true or false depending on whether the query is a stored procedure or not.

You can explicitly tell Hibernate what column aliases to use with <return-property>, instead of using the {}-syntax to let Hibernate inject its own aliases.For example:

<sql-query name="mySqlQuery">
    <return alias="person" class="eg.Person">
        <return-property name="name" column="myName"/>
        <return-property name="age" column="myAge"/>
        <return-property name="sex" column="mySex"/>
    </return>
    SELECT person.NAME AS myName,
           person.AGE AS myAge,
           person.SEX AS mySex,
    FROM PERSON person WHERE person.NAME LIKE :name
</sql-query>

<return-property> also works with multiple columns. This solves a limitation with the {}-syntax which cannot allow fine grained control of multi-column properties.

<sql-query name="organizationCurrentEmployments">
    <return alias="emp" class="Employment">
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
        <return-property name="endDate" column="myEndDate"/>
    </return>
        SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
        STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
        REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
        FROM EMPLOYMENT
        WHERE EMPLOYER = :id AND ENDDATE IS NULL
        ORDER BY STARTDATE ASC
</sql-query>

In this example <return-property> was used in combination with the {}-syntax for injection. This allows users to choose how they want to refer column and properties.

If your mapping has a discriminator you must use <return-discriminator> to specify the discriminator column.

Hibernate provides support for queries via stored procedures and functions. Most of the following documentation is equivalent for both. The stored procedure/function must return a resultset as the first out-parameter to be able to work with Hibernate. An example of such a stored function in Oracle 9 and higher is as follows:

CREATE OR REPLACE FUNCTION selectAllEmployments
    RETURN SYS_REFCURSOR
AS
    st_cursor SYS_REFCURSOR;
BEGIN
    OPEN st_cursor FOR
 SELECT EMPLOYEE, EMPLOYER,
 STARTDATE, ENDDATE,
 REGIONCODE, EID, VALUE, CURRENCY
 FROM EMPLOYMENT;
      RETURN  st_cursor;
 END;

To use this query in Hibernate you need to map it via a named query.

<sql-query name="selectAllEmployees_SP" callable="true">
    <return alias="emp" class="Employment">
        <return-property name="employee" column="EMPLOYEE"/>
        <return-property name="employer" column="EMPLOYER"/>
        <return-property name="startDate" column="STARTDATE"/>
        <return-property name="endDate" column="ENDDATE"/>
        <return-property name="regionCode" column="REGIONCODE"/>
        <return-property name="id" column="EID"/>
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
    </return>
    { ? = call selectAllEmployments() }
</sql-query>

Stored procedures currently only return scalars and entities. <return-join> and <load-collection> are not supported.

Hibernate can use custom SQL for create, update, and delete operations. The SQL can be overridden at the statement level or inidividual column level. This section describes statement overrides. For columns, see ???. Example 15.11, “Custom CRUD via annotations” shows how to define custom SQL operatons using annotations.


@SQLInsert, @SQLUpdate, @SQLDelete, @SQLDeleteAll respectively override the INSERT, UPDATE, DELETE, and DELETE all statement. The same can be achieved using Hibernate mapping files and the <sql-insert>, <sql-update> and <sql-delete> nodes. This can be seen in Example 15.12, “Custom CRUD XML”.


If you expect to call a store procedure, be sure to set the callable attribute to true. In annotations as well as in xml.

To check that the execution happens correctly, Hibernate allows you to define one of those three strategies:

  • none: no check is performed: the store procedure is expected to fail upon issues

  • count: use of rowcount to check that the update is successful

  • param: like COUNT but using an output parameter rather that the standard mechanism

To define the result check style, use the check parameter which is again available in annoations as well as in xml.

You can use the exact same set of annotations respectively xml nodes to override the collection related statements -see Example 15.13, “Overriding SQL statements for collections using annotations”.


Tip

The parameter order is important and is defined by the order Hibernate handles properties. You can see the expected order by enabling debug logging for the org.hibernate.persister.entity level. With this level enabled Hibernate will print out the static SQL that is used to create, update, delete etc. entities. (To see the expected sequence, remember to not include your custom SQL through annotations or mapping files as that will override the Hibernate generated static sql)

Overriding SQL statements for secondary tables is also possible using @org.hibernate.annotations.Table and either (or all) attributes sqlInsert, sqlUpdate, sqlDelete:


The previous example also shows that you can give a comment to a given table (primary or secondary): This comment will be used for DDL generation.

Tip

The SQL is directly executed in your database, so you can use any dialect you like. This will, however, reduce the portability of your mapping if you use database specific SQL.

Last but not least, stored procedures are in most cases required to return the number of rows inserted, updated and deleted. Hibernate always registers the first statement parameter as a numeric output parameter for the CUD operations:


You can also declare your own SQL (or HQL) queries for entity loading. As with inserts, updates, and deletes, this can be done at the individual column level as described in ??? or at the statement level. Here is an example of a statement level override:

<sql-query name="person">
    <return alias="pers" class="Person" lock-mode="upgrade"/>
    SELECT NAME AS {pers.name}, ID AS {pers.id}
    FROM PERSON
    WHERE ID=?
    FOR UPDATE
</sql-query>

This is just a named query declaration, as discussed earlier. You can reference this named query in a class mapping:

<class name="Person">
    <id name="id">
        <generator class="increment"/>
    </id>
    <property name="name" not-null="true"/>
    <loader query-ref="person"/>
</class>

This even works with stored procedures.

You can even define a query for collection loading:

<set name="employments" inverse="true">
    <key/>
    <one-to-many class="Employment"/>
    <loader query-ref="employments"/>
</set>
<sql-query name="employments">
    <load-collection alias="emp" role="Person.employments"/>
    SELECT {emp.*}
    FROM EMPLOYMENT emp
    WHERE EMPLOYER = :id
    ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query>

You can also define an entity loader that loads a collection by join fetching:

<sql-query name="person">
    <return alias="pers" class="Person"/>
    <return-join alias="emp" property="pers.employments"/>
    SELECT NAME AS {pers.*}, {emp.*}
    FROM PERSON pers
    LEFT OUTER JOIN EMPLOYMENT emp
        ON pers.ID = emp.PERSON_ID
    WHERE ID=?
</sql-query>

The annotation equivalent <loader> is the @Loader annotation as seen in Example 15.11, “Custom CRUD via annotations”.

There are 3 main approaches to isolating information in these multi-tenant systems which goes hand-in-hand with different database schema definitions and JDBC setups.

Using Hibernate with multi-tenant data comes down to both an API and then integration piece(s). As usual Hibernate strives to keep the API simple and isolated from any underlying integration complexities. The API is really just defined by passing the tenant identifier as part of opening any session.


Additionally, when specifying configuration, a org.hibernate.MultiTenancyStrategy should be named using the hibernate.multiTenancy setting. Hibernate will perform validations based on the type of strategy you specify. The strategy here correlates to the isolation approach discussed above.

NONE

(the default) No multi-tenancy is expected. In fact, it is considered an error if a tenant identifier is specified when opening a session using this strategy.

SCHEMA

Correlates to the separate schema approach. It is an error to attempt to open a session without a tenant identifier using this strategy. Additionally, a MultiTenantConnectionProvider must be specified.

DATABASE

Correlates to the separate database approach. It is an error to attempt to open a session without a tenant identifier using this strategy. Additionally, a MultiTenantConnectionProvider must be specified.

DISCRIMINATOR

Correlates to the partitioned (discriminator) approach. It is an error to attempt to open a session without a tenant identifier using this strategy. This strategy is not yet implemented in Hibernate as of 4.0 and 4.1. Its support is planned for 5.0.

org.hibernate.context.spi.CurrentTenantIdentifierResolver is a contract for Hibernate to be able to resolve what the application considers the current tenant identifier. The implementation to use is either passed directly to Configuration via its setCurrentTenantIdentifierResolver method. It can also be specified via the hibernate.tenant_identifier_resolver setting.

There are 2 situations where CurrentTenantIdentifierResolver is used:

Additionally, if the CurrentTenantIdentifierResolver implementation returns true for its validateExistingCurrentSessions method, Hibernate will make sure any existing sessions that are found in scope have a matching tenant identifier. This capability is only pertinent when the CurrentTenantIdentifierResolver is used in current-session settings.


The approach above is valid for the DATABASE approach. It is also valid for the SCHEMA approach provided the underlying database allows naming the schema to which to connect in the connection URL.

Example 16.3. Implementing MultiTenantConnectionProvider using single connection pool

/**
 * Simplisitc implementation for illustration purposes showing a single connection pool used to serve
 * multiple schemas using "connection altering".  Here we use the T-SQL specific USE command; Oracle
 * users might use the ALTER SESSION SET SCHEMA command; etc.
 */
public class MultiTenantConnectionProviderImpl
		implements MultiTenantConnectionProvider, Stoppable {
	private final ConnectionProvider connectionProvider = ConnectionProviderUtils.buildConnectionProvider( "master" );

	@Override
	public Connection getAnyConnection() throws SQLException {
		return connectionProvider.getConnection();
	}

	@Override
	public void releaseAnyConnection(Connection connection) throws SQLException {
		connectionProvider.closeConnection( connection );
	}

	@Override
	public Connection getConnection(String tenantIdentifier) throws SQLException {
		final Connection connection = getAnyConnection();
		try {
			connection.createStatement().execute( "USE " + tenanantIdentifier );
		}
		catch ( SQLException e ) {
			throw new HibernateException(
					"Could not alter JDBC connection to specified schema [" +
							tenantIdentifier + "]",
					e
			);
		}
		return connection;
	}

	@Override
	public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
		try {
			connection.createStatement().execute( "USE master" );
		}
		catch ( SQLException e ) {
			// on error, throw an exception to make sure the connection is not returned to the pool.
			// your requirements may differ
			throw new HibernateException(
					"Could not alter JDBC connection to specified schema [" +
							tenantIdentifier + "]",
					e
			);
		}
		connectionProvider.closeConnection( connection );
	}

	...
}

This approach is only relevant to the SCHEMA approach.

The Enterprise OSGi specification includes container-managed JPA. The container is responsible for discovering persistence units in bundles and automatically creating the EntityManagerFactory (one EMF per PU). It uses the JPA provider (hibernate-osgi) that has registered itself with the OSGi PersistenceProvider service.

Hibernate also supports the use of JPA through hibernate-entitymanager, unmanaged by the OSGi container. The client bundle is responsible for managing the EntityManagerFactory and EntityManagers.

Native Hibernate use is also supported. The client bundle is responsible for managing the SessionFactory and Sessions.

The unmanaged-native demo project displays the use of optional Hibernate modules. Each module adds additional dependency bundles that must first be activated, either manually or through an additional feature. As of ORM 4.2, Envers is fully supported. Support for C3P0, Proxool, EhCache, and Infinispan were added in 4.3, however none of their 3rd party libraries currently work in OSGi (lots of ClassLoader problems, etc.). We're tracking the issues in JIRA.

Multiple contracts exist to allow applications to integrate with and extend Hibernate capabilities. Most apps utilize JDK services to provide their implementations. hibernate-osgi supports the same extensions through OSGi services. Implement and register them in any of the three configurations. hibernate-osgi will discover and integrate them during EMF/SF bootstrapping. Supported extension points are as follows. The specified interface should be used during service registration.

  • org.hibernate.integrator.spi.Integrator (as of 4.2)
  • org.hibernate.boot.registry.selector.StrategyRegistrationProvider (as of 4.3)
  • org.hibernate.boot.model.TypeContributor (as of 4.3)
  • JTA's javax.transaction.TransactionManager and javax.transaction.UserTransaction (as of 4.2), however these are typically provided by the OSGi container.

The easiest way to register extension point implementations is through a blueprint.xml file. Add OSGI-INF/blueprint/blueprint.xml to your classpath. Envers' blueprint is a great example:


Extension points can also be registered programmatically with BundleContext#registerService, typically within your BundleActivator#start.

  • Technically, multiple persistence units are supported by Enterprise OSGi JPA and unmanaged Hibernate JPA use. However, we cannot currently support this in OSGi. In Hibernate 4, only one instance of the OSGi-specific ClassLoader is used per Hibernate bundle, mainly due to heavy use of static TCCL utilities. We hope to support one OSGi ClassLoader per persistence unit in Hibernate 5.

  • Scanning is supported to find non-explicitly listed entities and mappings. However, they MUST be in the same bundle as your persistence unit (fairly typical anyway). Our OSGi ClassLoader only considers the "requesting bundle" (hence the requirement on using services to create EMF/SF), rather than attempting to scan all available bundles. This is primarily for versioning considerations, collision protections, etc.

  • Some containers (ex: Aries) always return true for PersistenceUnitInfo#excludeUnlistedClasses, even if your persistence.xml explicitly has exclude-unlisted-classes set to false. They claim it's to protect JPA providers from having to implement scanning ("we handle it for you"), even though we still want to support it in many cases. The work around is to set hibernate.archive.autodetection to, for example, hbm,class. This tells hibernate to ignore the excludeUnlistedClasses value and scan for *.hbm.xml and entities regardless.

  • Scanning does not currently support annotated packages on package-info.java.

  • Currently, Hibernate OSGi is primarily tested using Apache Karaf and Apache Aries JPA. Additional testing is needed with Equinox, Gemini, and other container providers.

  • Hibernate ORM has many dependencies that do not currently provide OSGi manifests. The QuickStart tutorials make heavy use of 3rd party bundles (SpringSource, ServiceMix) or the wrap:... operator.

To audit changes that are performed on an entity, you only need two things: the hibernate-envers jar on the classpath and an @Audited annotation on the entity.

Important

Unlike in previous versions, you no longer need to specify listeners in the Hibernate configuration file. Just putting the Envers jar on the classpath is enough - listeners will be registered automatically.

And that's all - you can create, modify and delete the entities as always. If you look at the generated schema for your entities, or at the data persisted by Hibernate, you will notice that there are no changes. However, for each audited entity, a new table is introduced - entity_table_AUD, which stores the historical data, whenever you commit a transaction. Envers automatically creates audit tables if hibernate.hbm2ddl.auto option is set to create, create-drop or update. Otherwise, to export complete database schema programatically, use org.hibernate.envers.tools.hbm2ddl.EnversSchemaGenerator. Appropriate DDL statements can be also generated with Ant task described later in this manual.

Instead of annotating the whole class and auditing all properties, you can annotate only some persistent properties with @Audited. This will cause only these properties to be audited.

The audit (history) of an entity can be accessed using the AuditReader interface, which can be obtained having an open EntityManager or Session via the AuditReaderFactory. See the javadocs for these classes for details on the functionality offered.

It is possible to configure various aspects of Hibernate Envers behavior, such as table names, etc.

Table 18.1. Envers Configuration Properties

Property nameDefault valueDescription
org.hibernate.envers.audit_table_prefix String that will be prepended to the name of an audited entity to create the name of the entity, that will hold audit information.
org.hibernate.envers.audit_table_suffix _AUD String that will be appended to the name of an audited entity to create the name of the entity, that will hold audit information. If you audit an entity with a table name Person, in the default setting Envers will generate a Person_AUD table to store historical data.
org.hibernate.envers.revision_field_name REV Name of a field in the audit entity that will hold the revision number.
org.hibernate.envers.revision_type_field_name REVTYPE Name of a field in the audit entity that will hold the type of the revision (currently, this can be: add, mod, del).
org.hibernate.envers.revision_on_collection_change true Should a revision be generated when a not-owned relation field changes (this can be either a collection in a one-to-many relation, or the field using "mappedBy" attribute in a one-to-one relation).
org.hibernate.envers.do_not_audit_optimistic_locking_field true When true, properties to be used for optimistic locking, annotated with @Version, will be automatically not audited (their history won't be stored; it normally doesn't make sense to store it).
org.hibernate.envers.store_data_at_delete false Should the entity data be stored in the revision when the entity is deleted (instead of only storing the id and all other properties as null). This is not normally needed, as the data is present in the last-but-one revision. Sometimes, however, it is easier and more efficient to access it in the last revision (then the data that the entity contained before deletion is stored twice).
org.hibernate.envers.default_schema null (same schema as table being audited) The default schema name that should be used for audit tables. Can be overridden using the @AuditTable(schema="...") annotation. If not present, the schema will be the same as the schema of the table being audited.
org.hibernate.envers.default_catalog null (same catalog as table being audited) The default catalog name that should be used for audit tables. Can be overridden using the @AuditTable(catalog="...") annotation. If not present, the catalog will be the same as the catalog of the normal tables.
org.hibernate.envers.audit_strategy org.hibernate.envers.strategy.DefaultAuditStrategy The audit strategy that should be used when persisting audit data. The default stores only the revision, at which an entity was modified. An alternative, the org.hibernate.envers.strategy.ValidityAuditStrategy stores both the start revision and the end revision. Together these define when an audit row was valid, hence the name ValidityAuditStrategy.
org.hibernate.envers.audit_strategy_validity_end_rev_field_name REVEND The column name that will hold the end revision number in audit entities. This property is only valid if the validity audit strategy is used.
org.hibernate.envers.audit_strategy_validity_store_revend_timestamp false Should the timestamp of the end revision be stored, until which the data was valid, in addition to the end revision itself. This is useful to be able to purge old Audit records out of a relational database by using table partitioning. Partitioning requires a column that exists within the table. This property is only evaluated if the ValidityAuditStrategy is used.
org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name REVEND_TSTMP Column name of the timestamp of the end revision until which the data was valid. Only used if the ValidityAuditStrategy is used, and org.hibernate.envers.audit_strategy_validity_store_revend_timestamp evaluates to true
org.hibernate.envers.use_revision_entity_with_native_id true Boolean flag that determines the strategy of revision number generation. Default implementation of revision entity uses native identifier generator. If current database engine does not support identity columns, users are advised to set this property to false. In this case revision numbers are created by preconfigured org.hibernate.id.enhanced.SequenceStyleGenerator. See:
  1. org.hibernate.envers.DefaultRevisionEntity
  2. org.hibernate.envers.enhanced.SequenceIdRevisionEntity
org.hibernate.envers.track_entities_changed_in_revision false Should entity types, that have been modified during each revision, be tracked. The default implementation creates REVCHANGES table that stores entity names of modified persistent objects. Single record encapsulates the revision identifier (foreign key to REVINFO table) and a string value. For more information refer to Section 18.5.1, “Tracking entity names modified during revisions” and Section 18.7.4, “Querying for entities modified in a given revision”.
org.hibernate.envers.global_with_modified_flag false, can be individually overriden with @Audited(withModifiedFlag=true) Should property modification flags be stored for all audited entities and all properties. When set to true, for all properties an additional boolean column in the audit tables will be created, filled with information if the given property changed in the given revision. When set to false, such column can be added to selected entities or properties using the @Audited annotation. For more information refer to Section 18.6, “Tracking entity changes at property level” and Section 18.7.3, “Querying for revisions of entity that modified given property”.
org.hibernate.envers.modified_flag_suffix _MOD The suffix for columns storing "Modified Flags". For example: a property called "age", will by default get modified flag with column name "age_MOD".
org.hibernate.envers.embeddable_set_ordinal_field_name SETORDINAL Name of column used for storing ordinal of the change in sets of embeddable elements.
org.hibernate.envers.cascade_delete_revision false While deleting revision entry, remove data of associated audited entities. Requires database support for cascade row removal.
org.hibernate.envers.allow_identifier_reuse false Guarantees proper validity audit strategy behavior when application reuses identifiers of deleted entities. Exactly one row with null end date exists for each identifier.

Important

The following configuration options have been added recently and should be regarded as experimental:

  1. org.hibernate.envers.track_entities_changed_in_revision
  2. org.hibernate.envers.using_modified_flag
  3. org.hibernate.envers.modified_flag_suffix

The name of the audit table can be set on a per-entity basis, using the @AuditTable annotation. It may be tedious to add this annotation to every audited entity, so if possible, it's better to use a prefix/suffix.

If you have a mapping with secondary tables, audit tables for them will be generated in the same way (by adding the prefix and suffix). If you wish to overwrite this behaviour, you can use the @SecondaryAuditTable and @SecondaryAuditTables annotations.

If you'd like to override auditing behaviour of some fields/properties inherited from @Mappedsuperclass or in an embedded component, you can apply the @AuditOverride(s) annotation on the subtype or usage site of the component.

If you want to audit a relation mapped with @OneToMany+@JoinColumn, please see Section 18.11, “Mapping exceptions” for a description of the additional @AuditJoinTable annotation that you'll probably want to use.

If you want to audit a relation, where the target entity is not audited (that is the case for example with dictionary-like entities, which don't change and don't have to be audited), just annotate it with @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED). Then, while reading historic versions of your entity, the relation will always point to the "current" related entity. By default Envers throws javax.persistence.EntityNotFoundException when "current" entity does not exist in the database. Apply @NotFound(action = NotFoundAction.IGNORE) annotation to silence the exception and assign null value instead. Hereby solution causes implicit eager loading of to-one relations.

If you'd like to audit properties of a superclass of an entity, which are not explicitly audited (which don't have the @Audited annotation on any properties or on the class), you can list the superclasses in the auditParents attribute of the @Audited annotation. Please note that auditParents feature has been deprecated. Use @AuditOverride(forClass = SomeEntity.class, isAudited = true/false) instead.

After the basic configuration it is important to choose the audit strategy that will be used to persist and retrieve audit information. There is a trade-off between the performance of persisting and the performance of querying the audit information. Currently there two audit strategies.

  1. The default audit strategy persists the audit data together with a start revision. For each row inserted, updated or deleted in an audited table, one or more rows are inserted in the audit tables, together with the start revision of its validity. Rows in the audit tables are never updated after insertion. Queries of audit information use subqueries to select the applicable rows in the audit tables. These subqueries are notoriously slow and difficult to index.

  2. The alternative is a validity audit strategy. This strategy stores the start-revision and the end-revision of audit information. For each row inserted, updated or deleted in an audited table, one or more rows are inserted in the audit tables, together with the start revision of its validity. But at the same time the end-revision field of the previous audit rows (if available) are set to this revision. Queries on the audit information can then use 'between start and end revision' instead of subqueries as used by the default audit strategy.

    The consequence of this strategy is that persisting audit information will be a bit slower, because of the extra updates involved, but retrieving audit information will be a lot faster. This can be improved by adding extra indexes.

When Envers starts a new revision, it creates a new revision entity which stores information about the revision. By default, that includes just

  1. revision number - An integral value (int/Integer or long/Long). Essentially the primary key of the revision

  2. revision timestamp - either a long/Long or java.util.Date value representing the instant at which the revision was made. When using a java.util.Date, instead of a long/Long for the revision timestamp, take care not to store it to a column data type which will loose precision.

Envers handles this information as an entity. By default it uses its own internal class to act as the entity, mapped to the REVINFO table. You can, however, supply your own approach to collecting this information which might be useful to capture additional details such as who made a change or the ip address from which the request came. There are 2 things you need to make this work.

  1. First, you will need to tell Envers about the entity you wish to use. Your entity must use the @org.hibernate.envers.RevisionEntity annotation. It must define the 2 attributes described above annotated with @org.hibernate.envers.RevisionNumber and @org.hibernate.envers.RevisionTimestamp, respectively. You can extend from org.hibernate.envers.DefaultRevisionEntity, if you wish, to inherit all these required behaviors.

    Simply add the custom revision entity as you do your normal entities. Envers will "find it". Note that it is an error for there to be multiple entities marked as @org.hibernate.envers.RevisionEntity

  2. Second, you need to tell Envers how to create instances of your revision entity which is handled by the newRevision method of the org.jboss.envers.RevisionListener interface.

    You tell Envers your custom org.hibernate.envers.RevisionListener implementation to use by specifying it on the @org.hibernate.envers.RevisionEntity annotation, using the value attribute. If your RevisionListener class is inaccessible from @RevisionEntity (e.g. exists in a different module), set org.hibernate.envers.revision_listener property to it's fully qualified name. Class name defined by the configuration parameter overrides revision entity's value attribute.

@Entity
@RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity {
    ...
}

public class MyCustomRevisionListener implements RevisionListener {
    public void newRevision(Object revisionEntity) {
        ( (MyCustomRevisionEntity) revisionEntity )...;
    }
}

An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information. The method accepts a persist parameter indicating whether the revision entity should be persisted prior to returning from this method. true ensures that the returned entity has access to its identifier value (revision number), but the revision entity will be persisted regardless of whether there are any audited entities changed. false means that the revision number will be null, but the revision entity will be persisted only if some audited entities have changed.


By default entity types that have been changed in each revision are not being tracked. This implies the necessity to query all tables storing audited data in order to retrieve changes made during specified revision. Envers provides a simple mechanism that creates REVCHANGES table which stores entity names of modified persistent objects. Single record encapsulates the revision identifier (foreign key to REVINFO table) and a string value.

Tracking of modified entity names can be enabled in three different ways:

  1. Set org.hibernate.envers.track_entities_changed_in_revision parameter to true. In this case org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity will be implicitly used as the revision log entity.

  2. Create a custom revision entity that extends org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity class.

    @Entity
    @RevisionEntity
    public class ExtendedRevisionEntity
                 extends DefaultTrackingModifiedEntitiesRevisionEntity {
        ...
    }
  3. Mark an appropriate field of a custom revision entity with @org.hibernate.envers.ModifiedEntityNames annotation. The property is required to be of Set<String> type.

    @Entity
    @RevisionEntity
    public class AnnotatedTrackingRevisionEntity {
        ...
    
        @ElementCollection
        @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
        @Column(name = "ENTITYNAME")
        @ModifiedEntityNames
        private Set<String> modifiedEntityNames;
        
        ...
    }

Users, that have chosen one of the approaches listed above, can retrieve all entities modified in a specified revision by utilizing API described in Section 18.7.4, “Querying for entities modified in a given revision”.

Users are also allowed to implement custom mechanism of tracking modified entity types. In this case, they shall pass their own implementation of org.hibernate.envers.EntityTrackingRevisionListener interface as the value of @org.hibernate.envers.RevisionEntity annotation. EntityTrackingRevisionListener interface exposes one method that notifies whenever audited entity instance has been added, modified or removed within current revision boundaries.

Example 18.2. Custom implementation of tracking entity classes modified during revisions

                    CustomEntityTrackingRevisionListener.java

public class CustomEntityTrackingRevisionListener
             implements EntityTrackingRevisionListener {
    @Override
    public void entityChanged(Class entityClass, String entityName,
                              Serializable entityId, RevisionType revisionType,
                              Object revisionEntity) {
        String type = entityClass.getName();
        ((CustomTrackingRevisionEntity)revisionEntity).addModifiedEntityType(type);
    }

    @Override
    public void newRevision(Object revisionEntity) {
    }
}
                    CustomTrackingRevisionEntity.java

@Entity
@RevisionEntity(CustomEntityTrackingRevisionListener.class)
public class CustomTrackingRevisionEntity {
    @Id
    @GeneratedValue
    @RevisionNumber
    private int customId;

    @RevisionTimestamp
    private long customTimestamp;

    @OneToMany(mappedBy="revision", cascade={CascadeType.PERSIST, CascadeType.REMOVE})
    private Set<ModifiedEntityTypeEntity> modifiedEntityTypes =
                                              new HashSet<ModifiedEntityTypeEntity>();
    
    public void addModifiedEntityType(String entityClassName) {
        modifiedEntityTypes.add(new ModifiedEntityTypeEntity(this, entityClassName));
    }
    
    ...
}
                    ModifiedEntityTypeEntity.java

@Entity
public class ModifiedEntityTypeEntity {
    @Id
    @GeneratedValue
    private Integer id;

    @ManyToOne
    private CustomTrackingRevisionEntity revision;
    
    private String entityClassName;
    
    ...
}
CustomTrackingRevisionEntity revEntity =
    getAuditReader().findRevision(CustomTrackingRevisionEntity.class, revisionNumber);
Set<ModifiedEntityTypeEntity> modifiedEntityTypes = revEntity.getModifiedEntityTypes()

By default the only information stored by Envers are revisions of modified entities. This approach lets user create audit queries based on historical values of entity's properties. Sometimes it is useful to store additional metadata for each revision, when you are interested also in the type of changes, not only about the resulting values. The feature described in Section 18.5.1, “Tracking entity names modified during revisions” makes it possible to tell which entities were modified in given revision. Feature described here takes it one step further. "Modification Flags" enable Envers to track which properties of audited entities were modified in a given revision.

Tracking entity changes at property level can be enabled by:

  1. setting org.hibernate.envers.global_with_modified_flag configuration property to true. This global switch will cause adding modification flags for all audited properties in all audited entities.

  2. using @Audited(withModifiedFlag=true) on a property or on an entity.

The trade-off coming with this functionality is an increased size of audit tables and a very little, almost negligible, performance drop during audit writes. This is due to the fact that every tracked property has to have an accompanying boolean column in the schema that stores information about the property's modifications. Of course it is Envers' job to fill these columns accordingly - no additional work by the developer is required. Because of costs mentioned, it is recommended to enable the feature selectively, when needed with use of the granular configuration means described above.

To see how "Modified Flags" can be utilized, check out the very simple query API that uses them: Section 18.7.3, “Querying for revisions of entity that modified given property”.

You can think of historic data as having two dimension. The first - horizontal - is the state of the database at a given revision. Thus, you can query for entities as they were at revision N. The second - vertical - are the revisions, at which entities changed. Hence, you can query for revisions, in which a given entity changed.

The queries in Envers are similar to Hibernate Criteria queries, so if you are common with them, using Envers queries will be much easier.

The main limitation of the current queries implementation is that you cannot traverse relations. You can only specify constraints on the ids of the related entities, and only on the "owning" side of the relation. This however will be changed in future releases.

Please note, that queries on the audited data will be in many cases much slower than corresponding queries on "live" data, as they involve correlated subselects.

In the future, queries will be improved both in terms of speed and possibilities, when using the valid-time audit strategy, that is when storing both start and end revisions for entities. See Section 18.2, “Configuration”.

The entry point for this type of queries is:

AuditQuery query = getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true);

You can add constraints to this query in the same way as to the previous one. There are some additional possibilities:

  1. using AuditEntity.revisionNumber() you can specify constraints, projections and order on the revision number, in which the audited entity was modified

  2. similarly, using AuditEntity.revisionProperty(propertyName) you can specify constraints, projections and order on a property of the revision entity, corresponding to the revision in which the audited entity was modified

  3. AuditEntity.revisionType() gives you access as above to the type of the revision (ADD, MOD, DEL).

Using these methods, you can order the query results by revision number, set projection or constraint the revision number to be greater or less than a specified value, etc. For example, the following query will select the smallest revision number, at which entity of class MyEntity with id entityId has changed, after revision number 42:

Number revision = (Number) getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true)
    .setProjection(AuditEntity.revisionNumber().min())
    .add(AuditEntity.id().eq(entityId))
    .add(AuditEntity.revisionNumber().gt(42))
    .getSingleResult();

The second additional feature you can use in queries for revisions is the ability to maximalize/minimize a property. For example, if you want to select the revision, at which the value of the actualDate for a given entity was larger then a given value, but as small as possible:

Number revision = (Number) getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true)
    // We are only interested in the first revision
    .setProjection(AuditEntity.revisionNumber().min())
    .add(AuditEntity.property("actualDate").minimize()
        .add(AuditEntity.property("actualDate").ge(givenDate))
        .add(AuditEntity.id().eq(givenEntityId)))
    .getSingleResult();

The minimize() and maximize() methods return a criteria, to which you can add constraints, which must be met by the entities with the maximized/minimized properties. AggregatedAuditExpression#computeAggregationInInstanceContext() enables the possibility to compute aggregated expression in the context of each entity instance separately. It turns out useful when querying for latest revisions of all entities of a particular type.

You probably also noticed that there are two boolean parameters, passed when creating the query. The first one, selectEntitiesOnly, is only valid when you don't set an explicit projection. If true, the result of the query will be a list of entities (which changed at revisions satisfying the specified constraints).

If false, the result will be a list of three element arrays. The first element will be the changed entity instance. The second will be an entity containing revision data (if no custom entity is used, this will be an instance of DefaultRevisionEntity). The third will be the type of the revision (one of the values of the RevisionType enumeration: ADD, MOD, DEL).

The second parameter, selectDeletedEntities, specifies if revisions, in which the entity was deleted should be included in the results. If yes, such entities will have the revision type DEL and all fields, except the id, null.

For the two types of queries described above it's possible to use special Audit criteria called hasChanged() and hasNotChanged() that makes use of the functionality described in Section 18.6, “Tracking entity changes at property level”. They're best suited for vertical queries, however existing API doesn't restrict their usage for horizontal ones. Let's have a look at following examples:

AuditQuery query = getAuditReader().createQuery()
    .forRevisionsOfEntity(MyEntity.class, false, true)
    .add(AuditEntity.id().eq(id));
    .add(AuditEntity.property("actualDate").hasChanged())
            

This query will return all revisions of MyEntity with given id, where the actualDate property has been changed. Using this query we won't get all other revisions in which actualDate wasn't touched. Of course nothing prevents user from combining hasChanged condition with some additional criteria - add method can be used here in a normal way.

AuditQuery query = getAuditReader().createQuery()
    .forEntitiesAtRevision(MyEntity.class, revisionNumber)
    .add(AuditEntity.property("prop1").hasChanged())
    .add(AuditEntity.property("prop2").hasNotChanged());
            

This query will return horizontal slice for MyEntity at the time revisionNumber was generated. It will be limited to revisions that modified prop1 but not prop2. Note that the result set will usually also contain revisions with numbers lower than the revisionNumber, so we cannot read this query as "Give me all MyEntities changed in revisionNumber with prop1 modified and prop2 untouched". To get such result we have to use the forEntitiesModifiedAtRevision query:

AuditQuery query = getAuditReader().createQuery()
    .forEntitiesModifiedAtRevision(MyEntity.class, revisionNumber)
    .add(AuditEntity.property("prop1").hasChanged())
    .add(AuditEntity.property("prop2").hasNotChanged());
            

For each audited entity (that is, for each entity containing at least one audited field), an audit table is created. By default, the audit table's name is created by adding a "_AUD" suffix to the original table name, but this can be overridden by specifying a different suffix/prefix in the configuration or per-entity using the @org.hibernate.envers.AuditTable annotation.

Audit table columns

  1. id of the original entity (this can be more then one column in the case of composite primary keys)

  2. revision number - an integer. Matches to the revision number in the revision entity table.

  3. revision type - a small integer

  4. audited fields from the original entity

The primary key of the audit table is the combination of the original id of the entity and the revision number - there can be at most one historic entry for a given entity instance at a given revision.

The current entity data is stored in the original table and in the audit table. This is a duplication of data, however as this solution makes the query system much more powerful, and as memory is cheap, hopefully this won't be a major drawback for the users. A row in the audit table with entity id ID, revision N and data D means: entity with id ID has data D from revision N upwards. Hence, if we want to find an entity at revision M, we have to search for a row in the audit table, which has the revision number smaller or equal to M, but as large as possible. If no such row is found, or a row with a "deleted" marker is found, it means that the entity didn't exist at that revision.

The "revision type" field can currently have three values: 0, 1, 2, which means ADD, MOD and DEL, respectively. A row with a revision of type DEL will only contain the id of the entity and no data (all fields NULL), as it only serves as a marker saying "this entity was deleted at that revision".

Additionally, there is a revision entity table which contains the information about the global revision. By default the generated table is named REVINFO and contains just 2 columns: ID and TIMESTAMP. A row is inserted into this table on each new revision, that is, on each commit of a transaction, which changes audited data. The name of this table can be configured, the name of its columns as well as adding additional columns can be achieved as discussed in Section 18.5, “Revision Log”.

While global revisions are a good way to provide correct auditing of relations, some people have pointed out that this may be a bottleneck in systems, where data is very often modified. One viable solution is to introduce an option to have an entity "locally revisioned", that is revisions would be created for it independently. This wouldn't enable correct versioning of relations, but wouldn't also require the REVINFO table. Another possibility is to introduce a notion of "revisioning groups": groups of entities which share revision numbering. Each such group would have to consist of one or more strongly connected component of the graph induced by relations between entities. Your opinions on the subject are very welcome on the forum! :)

If you'd like to generate the database schema file with the Hibernate Tools Ant task, you'll probably notice that the generated file doesn't contain definitions of audit tables. To generate also the audit tables, you simply need to use org.hibernate.tool.ant.EnversHibernateToolTask instead of the usual org.hibernate.tool.ant.HibernateToolTask. The former class extends the latter, and only adds generation of the version entities. So you can use the task just as you used to.

For example:

<target name="schemaexport" depends="build-demo"
  description="Exports a generated schema to DB and file">
  <taskdef name="hibernatetool"
    classname="org.hibernate.tool.ant.EnversHibernateToolTask"
    classpathref="build.demo.classpath"/>

  <hibernatetool destdir=".">
    <classpath>
      <fileset refid="lib.hibernate" />
      <path location="${build.demo.dir}" />
      <path location="${build.main.dir}" />
    </classpath>
    <jpaconfiguration persistenceunit="ConsolePU" />
    <hbm2ddl
      drop="false"
      create="true"
      export="false"
      outputfilename="versioning-ddl.sql"
      delimiter=";"
      format="true"/>
  </hibernatetool>
</target>

Will generate the following schema:

    create table Address (
        id integer generated by default as identity (start with 1),
        flatNumber integer,
        houseNumber integer,
        streetName varchar(255),
        primary key (id)
    );

    create table Address_AUD (
        id integer not null,
        REV integer not null,
        flatNumber integer,
        houseNumber integer,
        streetName varchar(255),
        REVTYPE tinyint,
        primary key (id, REV)
    );

    create table Person (
        id integer generated by default as identity (start with 1),
        name varchar(255),
        surname varchar(255),
        address_id integer,
        primary key (id)
    );

    create table Person_AUD (
        id integer not null,
        REV integer not null,
        name varchar(255),
        surname varchar(255),
        REVTYPE tinyint,
        address_id integer,
        primary key (id, REV)
    );

    create table REVINFO (
        REV integer generated by default as identity (start with 1),
        REVTSTMP bigint,
        primary key (REV)
    );

    alter table Person
        add constraint FK8E488775E4C3EA63
        foreign key (address_id)
        references Address;
    

Generally SQL tables must be partitioned on a column that exists within the table. As a rule it makes sense to use either the end revision or the end revision timestamp column for partioning of audit tables.

The reason why the end revision information should be used for audit table partioning is based on the assumption that audit tables should be partionioned on an 'increasing level of interestingness', like so:

  1. A couple of partitions with audit data that is not very (or no longer) interesting. This can be stored on slow media, and perhaps even be purged eventually.

  2. Some partitions for audit data that is potentially interesting.

  3. One partition for audit data that is most likely to be interesting. This should be stored on the fastest media, both for reading and writing.

In order to determine a suitable column for the 'increasing level of interestingness', consider a simplified example of a salary registration for an unnamed agency.

Currently, the salary table contains the following rows for a certain person X:


The salary for the current fiscal year (2010) is unknown. The agency requires that all changes in registered salaries for a fiscal year are recorded (i.e. an audit trail). The rationale behind this is that decisions made at a certain date are based on the registered salary at that time. And at any time it must be possible reproduce the reason why a certain decision was made at a certain date.

The following audit information is available, sorted on in order of occurrence:


  1. Hibernate main page

  2. Forum

  3. JIRA issue tracker (when adding issues concerning Envers, be sure to select the "envers" component!)

  4. IRC channel

  5. Envers Blog

  6. FAQ

Originally, Hibernate would always require that users specify which dialect to use. In the case of users looking to simultaneously target multiple databases with their build that was problematic. Generally this required their users to configure the Hibernate dialect or defining their own method of setting that value.

Starting with version 3.2, Hibernate introduced the notion of automatically detecting the dialect to use based on the java.sql.DatabaseMetaData obtained from a java.sql.Connection to that database. This was much better, expect that this resolution was limited to databases Hibernate know about ahead of time and was in no way configurable or overrideable.

Starting with version 3.3, Hibernate has a fare more powerful way to automatically determine which dialect to should be used by relying on a series of delegates which implement the org.hibernate.dialect.resolver.DialectResolver which defines only a single method:

public Dialect resolveDialect(DatabaseMetaData metaData) throws JDBCConnectionException

The basic contract here is that if the resolver 'understands' the given database metadata then it returns the corresponding Dialect; if not it returns null and the process continues to the next resolver. The signature also identifies org.hibernate.exception.JDBCConnectionException as possibly being thrown. A JDBCConnectionException here is interpreted to imply a "non transient" (aka non-recoverable) connection problem and is used to indicate an immediate stop to resolution attempts. All other exceptions result in a warning and continuing on to the next resolver.

The cool part about these resolvers is that users can also register their own custom resolvers which will be processed ahead of the built-in Hibernate ones. This might be useful in a number of different situations: it allows easy integration for auto-detection of dialects beyond those shipped with HIbernate itself; it allows you to specify to use a custom dialect when a particular database is recognized; etc. To register one or more resolvers, simply specify them (seperated by commas, tabs or spaces) using the 'hibernate.dialect_resolvers' configuration setting (see the DIALECT_RESOLVERS constant on org.hibernate.cfg.Environment).

When considering portability between databases, another important decision is selecting the identifier generation stratagy you want to use. Originally Hibernate provided the native generator for this purpose, which was intended to select between a sequence, identity, or table strategy depending on the capability of the underlying database. However, an insidious implication of this approach comes about when targtetting some databases which support identity generation and some which do not. identity generation relies on the SQL definition of an IDENTITY (or auto-increment) column to manage the identifier value; it is what is known as a post-insert generation strategy becauase the insert must actually happen before we can know the identifier value. Because Hibernate relies on this identifier value to uniquely reference entities within a persistence context it must then issue the insert immediately when the users requests the entitiy be associated with the session (like via save() e.g.) regardless of current transactional semantics.

Note

Hibernate was changed slightly once the implication of this was better understood so that the insert is delayed in cases where that is feasible.

The underlying issue is that the actual semanctics of the application itself changes in these cases.

Starting with version 3.2.3, Hibernate comes with a set of enhanced identifier generators targetting portability in a much different way.

Note

There are specifically 2 bundled enhancedgenerators:

  • org.hibernate.id.enhanced.SequenceStyleGenerator

  • org.hibernate.id.enhanced.TableGenerator

The idea behind these generators is to port the actual semantics of the identifer value generation to the different databases. For example, the org.hibernate.id.enhanced.SequenceStyleGenerator mimics the behavior of a sequence on databases which do not support sequences by using a table.

JPA portability * HQL/JPQL differences * naming strategies * basic types * simple id types * generated id types * composite ids and many-to-one * "embedded composite identifiers"

The legacy way to bootstrap a SessionFactory is via the org.hibernate.cfg.Configuration object. Configuration represents, essentially, a single point for specifying all aspects of building the SessionFactory: everything from settings, to mappings, to strategies, etc. I like to think of Configuration as a big pot to which we add a bunch of stuff (mappings, settings, etc) and from which we eventually get a SessionFactory.

Note

There are some significant draw backs to this approach which led to its deprecation and the development of the new approach, which is discussed in Section 3.1, “Native Bootstrapping”. Configuration is semi-deprecated but still available for use, in a limited form that eliminates these draw backs. "Under the covers", Configuration uses the new bootstrapping code, so the things available there as also available here in terms of auto-discovery.

You can obtain the Configuration by instantiating it directly. You then specify mapping metadata (XML mapping documents, annotated classes) that describe your applications object model and its mapping to a SQL database.


There are other ways to specify Configuration information, including:

  • Place a file named hibernate.properties in a root directory of the classpath
  • Pass an instance of java.util.Properties to Configuration#setProperties
  • Via a Hibernate cfg.xml file
  • System properties using java `-Dproperty=value`

Mapping Configuration methods to the corresponding methods in the new APIs..

Mapping metadata

Configuration#addFile
MetadataSources#addFile
Configuration#add(XmlDocument)
No replacement
Configuration#addXML
No replacement
Configuration#addCacheableFile
MetadataSources#addCacheableFile
Configuration#addURL
MetadataSources#addURL
Configuration#addInputStream
MetadataSources#addInputStream
Configuration#addResource
MetadataSources#addResource
Configuration#addClass
MetadataSources#addClass
Configuration#addAnnotatedClass
MetadataSources#addAnnotatedClass
Configuration#addPackage
MetadataSources#addPackage
Configuration#addJar
MetadataSources#addJar
Configuration#addDirectory
MetadataSources#addDirectory
Configuration#registerTypeContributor
MetadataBuilder#applyTypes
Configuration#registerTypeOverride
MetadataBuilder#applyBasicType

Settings

Configuration#setProperty
StandardServiceRegistryBuilder#applySetting
Configuration#setProperties
No replacement
Configuration#addProperties
StandardServiceRegistryBuilder#applySettings
Configuration#setNamingStrategy
No replacement. NamingStrategy split into implicit/physical strategies
Configuration#setImplicitNamingStrategy
MetadataBuilder#setImplicitNamingStrategy
Configuration#setPhysicalNamingStrategy
MetadataBuilder#setPhysicalNamingStrategy
Configuration#configure
StandardServiceRegistryBuilder#configure
Configuration#setInterceptor
SessionFactoryBuilder#applyInterceptor
Configuration#setEntityNotFoundDelegate
SessionFactoryBuilder#applyEntityNotFoundDelegate
Configuration#setSessionFactoryObserver
SessionFactoryBuilder#addSessionFactoryObservers
Configuration#setCurrentTenantIdentifierResolver
SessionFactoryBuilder#applyCurrentTenantIdentifierResolver

Note

This appendix covers the legacy Hibernate org.hibernate.Criteria API, which should be considered deprecated. New development should focus on the JPA javax.persistence.criteria.CriteriaQuery API. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery. For details on the JPA APIs, see Chapter 14, Criteria.

This information is copied as-is from the older Hibernate documentation.

Hibernate features an intuitive, extensible criteria query API.

An individual query criterion is an instance of the interface org.hibernate.criterion.Criterion. The class org.hibernate.criterion.Restrictions defines factory methods for obtaining certain built-in Criterion types.

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .add( Restrictions.between("weight", minWeight, maxWeight) )
    .list();

Restrictions can be grouped logically.

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .add( Restrictions.or(
        Restrictions.eq( "age", new Integer(0) ),
        Restrictions.isNull("age")
    ) )
    .list();
List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
    .add( Restrictions.disjunction()
        .add( Restrictions.isNull("age") )
        .add( Restrictions.eq("age", new Integer(0) ) )
        .add( Restrictions.eq("age", new Integer(1) ) )
        .add( Restrictions.eq("age", new Integer(2) ) )
    ) )
    .list();

There are a range of built-in criterion types (Restrictions subclasses). One of the most useful allows you to specify SQL directly.

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
    .list();

The {alias} placeholder will be replaced by the row alias of the queried entity.

You can also obtain a criterion from a Property instance. You can create a Property by calling Property.forName():

Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.disjunction()
        .add( age.isNull() )
        .add( age.eq( new Integer(0) ) )
        .add( age.eq( new Integer(1) ) )
        .add( age.eq( new Integer(2) ) )
    ) )
    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
    .list();

By navigating associations using createCriteria() you can specify constraints upon related entities:

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "F%") )
    .createCriteria("kittens")
        .add( Restrictions.like("name", "F%") )
    .list();

The second createCriteria() returns a new instance of Criteria that refers to the elements of the kittens collection.

There is also an alternate form that is useful in certain circumstances:

List cats = sess.createCriteria(Cat.class)
    .createAlias("kittens", "kt")
    .createAlias("mate", "mt")
    .add( Restrictions.eqProperty("kt.name", "mt.name") )
    .list();

(createAlias() does not create a new instance of Criteria.)

The kittens collections held by the Cat instances returned by the previous two queries are not pre-filtered by the criteria. If you want to retrieve just the kittens that match the criteria, you must use a ResultTransformer.

List cats = sess.createCriteria(Cat.class)
    .createCriteria("kittens", "kt")
        .add( Restrictions.eq("name", "F%") )
    .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
    .list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
    Map map = (Map) iter.next();
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
    Cat kitten = (Cat) map.get("kt");
}

Additionally you may manipulate the result set using a left outer join:

		List cats = session.createCriteria( Cat.class )
                       .createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") )
                       .addOrder(Order.asc("mt.age"))
                       .list();
	
	

This will return all of the Cats with a mate whose name starts with "good" ordered by their mate's age, and all cats who do not have a mate. This is useful when there is a need to order or limit in the database prior to returning complex/large result sets, and removes many instances where multiple queries would have to be performed and the results unioned by java in memory.

Without this feature, first all of the cats without a mate would need to be loaded in one query.

A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.

Thirdly, in memory; the lists would need to be joined manually.

When using criteria against collections, there are two distinct cases. One is if the collection contains entities (eg. <one-to-many/> or <many-to-many/>) or components (<composite-element/> ), and the second is if the collection contains scalar values (<element/>). In the first case, the syntax is as given above in the section Section B.4, “Associations” where we restrict the kittens collection. Essentially we create a Criteria object against the collection property and restrict the entity or component properties using that instance.

For queryng a collection of basic values, we still create the Criteria object against the collection, but to reference the value, we use the special property "elements". For an indexed collection, we can also reference the index property using the special property "indices".

		List cats = session.createCriteria(Cat.class)
			.createCriteria("nickNames")
				.add(Restrictions.eq("elements", "BadBoy"))
			.list();
	

The class org.hibernate.criterion.Projections is a factory for Projection instances. You can apply a projection to a query by calling setProjection().

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.rowCount() )
    .add( Restrictions.eq("color", Color.BLACK) )
    .list();
List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount() )
        .add( Projections.avg("weight") )
        .add( Projections.max("weight") )
        .add( Projections.groupProperty("color") )
    )
    .list();

There is no explicit "group by" necessary in a criteria query. Certain projection types are defined to be grouping projections, which also appear in the SQL group by clause.

An alias can be assigned to a projection so that the projected value can be referred to in restrictions or orderings. Here are two different ways to do this:

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
    .addOrder( Order.asc("colr") )
    .list();
List results = session.createCriteria(Cat.class)
    .setProjection( Projections.groupProperty("color").as("colr") )
    .addOrder( Order.asc("colr") )
    .list();

The alias() and as() methods simply wrap a projection instance in another, aliased, instance of Projection. As a shortcut, you can assign an alias when you add the projection to a projection list:

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount(), "catCountByColor" )
        .add( Projections.avg("weight"), "avgWeight" )
        .add( Projections.max("weight"), "maxWeight" )
        .add( Projections.groupProperty("color"), "color" )
    )
    .addOrder( Order.desc("catCountByColor") )
    .addOrder( Order.desc("avgWeight") )
    .list();
List results = session.createCriteria(Domestic.class, "cat")
    .createAlias("kittens", "kit")
    .setProjection( Projections.projectionList()
        .add( Projections.property("cat.name"), "catName" )
        .add( Projections.property("kit.name"), "kitName" )
    )
    .addOrder( Order.asc("catName") )
    .addOrder( Order.asc("kitName") )
    .list();

You can also use Property.forName() to express projections:

List results = session.createCriteria(Cat.class)
    .setProjection( Property.forName("name") )
    .add( Property.forName("color").eq(Color.BLACK) )
    .list();
List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount().as("catCountByColor") )
        .add( Property.forName("weight").avg().as("avgWeight") )
        .add( Property.forName("weight").max().as("maxWeight") )
        .add( Property.forName("color").group().as("color" )
    )
    .addOrder( Order.desc("catCountByColor") )
    .addOrder( Order.desc("avgWeight") )
    .list();

The DetachedCriteria class allows you to create a query outside the scope of a session and then execute it using an arbitrary Session.

DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
    .add( Property.forName("sex").eq('F') );
    
Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();

A DetachedCriteria can also be used to express a subquery. Criterion instances involving subqueries can be obtained via Subqueries or Property.

DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
    .setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
    .add( Property.forName("weight").gt(avgWeight) )
    .list();
DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
    .setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
    .add( Subqueries.geAll("weight", weights) )
    .list();

Correlated subqueries are also possible:

DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
    .setProjection( Property.forName("weight").avg() )
    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class, "cat")
    .add( Property.forName("weight").gt(avgWeightForSex) )
    .list();

Example of multi-column restriction based on a subquery:

DetachedCriteria sizeQuery = DetachedCriteria.forClass( Man.class )
    .setProjection( Projections.projectionList().add( Projections.property( "weight" ) )
                                                .add( Projections.property( "height" ) ) )
    .add( Restrictions.eq( "name", "John" ) );
session.createCriteria( Woman.class )
    .add( Subqueries.propertiesEq( new String[] { "weight", "height" }, sizeQuery ) )
    .list();