Sessions
The core of database operations in Hibernate is the lightweight, not-thread-safe net.sf.hibernate.Session object. Session objects are obtained from instances of the heavyweight, thread-safe net.sf.hibernate.Session Factory. A SessionFactory is obtained from a Configuration, in turn a heavy, expensive-to-create, one-time use class. Typically, you will use a singleton pattern to obtain a SessionFactory, and the logic for initializing the SessionFactory will include the use of a Configuration object. For more details on the relationship between Configuration, Session Factory, Session, transactions, and the ordering of statements within a particular session, see Chapter 9.
Session object are lightweight and not-thread-safe, and typically are created and disposed of frequently.
Setting up the Configuration
A Configuration object is created once, typically as part of the launching process of your application. The primary task of a Configuration object is to load and process the various *.hbm.xml files, binding them to the relevant persistent code, and returning an appropriately configured SessionFactory.
The list of methods in Table 6.1 is not complete. For a complete list, refer to the Hibernate javadoc (Hibernate_install_dir \doc\api\index.html). The summary shown in Table 6.1 illustrates the range of options available for storing configuration data.
Table 6.1. Adding Mapping FilesaddClass() | Uses the class name and package statement to load the *.hbm.xml. | addDirectory() | Loads all of the *.hbm.xml files from a particular directory. | addDocument() | Adds a mapping as already loaded by a DOM object. | addFile() | Reads the mapping from a particular file (may have an extension other than *.hbm.xml). | addInputStream() | Reads the mapping from a supplied java.io.InputStream. | addJar() | Reads the *.hbm.xml file from a specified JAR file. | addUrl() | Reads the mapping file from a specified URL. | addXML() | Reads the mapping as passed by an arbitrary String (useful for dynamic mapping generation, perhaps by a Hibernate-enabled tool). | configure() | Reads the mapping files and properties as specified by a hibernate.cfg.xml file. | configure(File) | Reads mapping files and properties as specified by a specific file (as per a hibernate.cfg.xml file). | configure(String) | Reads mapping files and properties as specified by a resource path (as per hibernate.cfg.xml file). | configure(URL) | Reads mapping files and properties as specified by a URL resource (as per hibernate.cfg.xml file). |
If you are using a hibernate.cfg.xml (or one of the configure() methods), you will define the connectivity properties in that file. Otherwise, these properties may be set at runtime using a java.util.Properties object via Configuration.addProperties(), Configuration .setProperties(), or individually using Configuration.set Property().
Alternatively, the connectivity may be configured using a hibernate .properties file placed on the class path.
Tables 6.3 through 6.6 describe additional options for the configuration of Hibernate.
Listing 6.1. Sample Minimal Properties File
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost/hibernate
hibernate.connection.username=root
hibernate.connection.password=
hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
Table 6.3. JNDI Datasource Connectivity Configuration PropertiesProperty Name | Purpose |
|---|
hibernate.connection.datasource | datasource JNDI name | hibernate.jndi.url | URL of the JNDI provider (optional) | hibernate.jndi.class | class of the JNDI InitialContextFactory (optional) | hibernate.connection.username | database user (optional) | hibernate.connection.password | database user password (optional) | hibernate.jndi.<propertyName> | Pass the property <propertyName> to the JNDI InitialContextFactory (optional) |
Table 6.6. Supported JTA Transaction ManagersApplication Server | Transaction Factory |
|---|
JBoss | net.sf.hibernate.transaction.JBoss TransactionManagerLookup | Weblogic | net.sf.hibernate.transaction.Weblogic TransactionManagerLookup | WebSphere | net.sf.hibernate.transaction.WebSphere TransactionManagerLookup | Orion | net.sf.hibernate.transaction.Orion TransactionManagerLookup | Resin | net.sf.hibernate.transaction.Resin TransactionManagerLookup | JOTM | net.sf.hibernate.transaction.JOTM TransactionManagerLookup | JOnAS | net.sf.hibernate.transaction.JOnAS TransactionManagerLookup | JRun4 | net.sf.hibernate.transaction. JRun4TransactionManagerLookup | Borland ES | net.sf.hibernate.transaction .BESTransactionManagerLookup | JNDI | net.sf.hibernate.transaction .JNDITransactionManagerLookup | Sun ONE Application Server 7 | net.sf.hibernate.transaction.Sun ONETransactionManagerLookup |
If you wish to use Hibernate (perhaps in conjunction with a pooling driver, as described in Chapter 10) to manage obtaining and releasing connections, you will want to set the properties as shown in Table 6.2.
Table 6.2. JDBC Connectivity Configuration PropertiesProperty Name | Purpose |
|---|
hibernate.connection.driver_class | JDBC driver class | hibernate.connection.url | JDBC URL | hibernate.connection.username | Database user account | hibernate.connection.password | Database user password | hibernate.connection.pool_size | Maximum number of pooled connections |
If you wish to use Hibernate in the context of an application server, you will probably rely on the application server's built-in JNDI-based datasource mechanism for managing connections. Table 6.3 shows the properties that must be set to allow Hibernate to connect to JNDI datasources.
Hibernate also offers a wide variety of configurable options, as shown in Table 6.4. You can use them to provide additional database connectivity options or to set performance options.
Table 6.4. Miscellaneous Optional Hibernate Configuration PropertiesProperty Name | Purpose | Value |
|---|
hibernate.dialect | The class name of a Hibernate Dialect enables certain platform-dependent features. | full.classname.of.Dialect (see Table 6.5) | hibernate.default_schema | Qualify unqualified table names with the given schema/table space in generated SQL. | SCHEMA_NAME | hibernate.session_factory_name | Bind this name to the SessionFactory. | jndi/composite/name | hibernate.use_outer_join | Enables outer join fetching. For more information on outer joins, see Chapter 8. | true | false | hibernate.max_fetch_depth | Set a maximum "depth" for the outer join fetch tree. For more information on outer joins, see Chapter 8. | recommended values between 0 and 3 | hibernate.jdbc.fetch_size | A nonzero value determines the JDBC fetch size (call Statement.setFetchSize()). | | hibernate.jdbc.batch_size | A nonzero value enables use of JDBC2 batch updates by Hibernate. | recommended values between 5 and 30 | hibernate.jdbc.use_scrollable_resultset | Enables use of JDBC2 scrollable result sets by Hibernate. This property is only necessary when using user-supplied connections. In all other instances Hibernate uses connection metadata. | true | false | hibernate.jdbc. use_streams_for_binary | Use streams when writing / reading binary or serializable types to/from JDBC. System-level property. | true | false | hibernate.cglib.use_reflection_optimizer | Enables use of CGLIB instead of runtime reflection (system-level property, default is to use CGLIB where possible). Defaults to true. Setting this to false can sometimes be useful when troubleshooting. | true | false | hibernate.connection Isolation | Set the JDBC transaction isolation level (optional) | 1, 2, 4, 8 (as defined by java.sql.Connection) | hibernate.connection.<propertyName> | Pass the JDBC property <propertyName> to DriverManager. getConnection(). | | hibernate.connection.provider_class | Class name of a custom ConnectionProvider. | Fully qualified class name of an implementation of net.sf.hibernate.connection.ConnectionProvider | hibernate.cache.provider_class | Class name of a custom CacheProvider. See Chapter 10 for more information | Fully qualified class name of an implementation of net.sf.hibernate. cache.CacheProvider | hibernate.cache. use_minimal_puts | Optimize second-level cache operation to minimize writes, at the cost of more frequent reads (useful for clustered caches). See Chapter 10 for more information. | TRue|false | hibernate.cache. use_query_cache | Enable the query cache. | true|false | hibernate.cache. region_prefix | Prefix to use for second-level cache region names. | prefix | hibernate.transaction.factory_class | Class name of a transactionFactory to use with Hibernate Transaction API. | Use JDBC Transactions: net.sf.hibernate.transaction.JDBCTransactionFactory To use JTA Transactions net.sf.hibernate. transaction. JTATransactionFactory | jta.UserTransaction | JNDI name used by JTATransactionFactory to obtain the JTA UserTransaction | jndi/composite/name | hibernate.transaction.manager_lookup_class | Class name of a TRansactionManager Lookuprequired when JVM-level caching is enabled in a JTA environment | A value from Table 6.6 or a custom implementation of net.sf.hibernate.transaction.Transaction ManagerLookup | hibernate.query.substitutions | Mapping from tokens in Hibernate queries to SQL tokens (tokens might be function or literal names, for example) | hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC | hibernate.show_sql | Write all SQL statements to console (a minimal alternative to the use of the logging functionality as described in Chapter 10) | true | false | hibernate.hbm2ddl.auto | Automatically export schema DDL. | update | create | create-drop |
Typically, Hibernate is able to automatically detect the proper SQL dialect to use based on the JDBC driver. You may wish to manually set the SQL dialect, either to ensure the proper dialect or for schema management (as described in Chapter 11). Table 6.5 shows the possible values for hibernate.dialect.
Table 6.5. Supported SQL DialectsDatabase | Dialect |
|---|
DB2 | net.sf.hibernate.dialect.DB2Dialect | DB2400 | net.sf.hibernate.dialect.DB2400Dialect | Firebird | net.sf.hibernate.dialect.FirebirdDialect | FrontBase | net.sf.hibernate.dialect.FrontBaseDialect | Generic | net.sf.hibernate.dialect.GenericDialect | HypersonicSQL | net.sf.hibernate.dialect.HSQLDialect | Informix | net.sf.hibernate.dialect.InformixDialect | Ingres | net.sf.hibernate.dialect.IngresDialect | Interbase | net.sf.hibernate.dialect.InterbaseDialect | Mckoi SQL | net.sf.hibernate.dialect.MckoiDialect | Microsoft SQL Server | net.sf.hibernate.dialect.SQLServerDialect | MySQL | net.sf.hibernate.dialect.MySQLDialect | Oracle 9 | net.sf.hibernate.dialect.Oracle9Dialect | Oracle | net.sf.hibernate.dialect.OracleDialect | Pointbase | net.sf.hibernate.dialect.PointbaseDialect | PostgreSQL | net.sf.hibernate.dialect.PostgreSQLDialect | Progress | net.sf.hibernate.dialect.ProgressDialect | SAP DB | net.sf.hibernate.dialect.SAPDBDialect | Sybase Anywhere | net.sf.hibernate.dialect.SybaseAnywhereDialect | Sybase 11.9.2 | net.sf.hibernate.dialect .Sybase11_9_2Dialect | Sybase | net.sf.hibernate.dialect.SybaseDialect |
Similarly, Hibernate offers support for JTA to manage your transactions. Table 6.6 shows the supported JTA transaction managers.
Obtaining the Session
Listing 6.2 shows an example of the use of the Configuration object to obtain a Session.
Listing 6.2. Typical Configuration Initialization
Configuration myConfiguration = new Configuration();
myConfiguration.addClass(Exam.class);
myConfiguration.addClass(Examresult.class);
myConfiguration.addClass(Course.class);
myConfiguration.addClass(Student.class);
// Sets up the session factory (used in the rest
// of the application).
sessionFactory = myConfiguration.buildSessionFactory();
Once a SessionFactory has been obtained, you will store this object somewhere (typically in a static variable) and use it throughout the rest of your application.
Most commonly, openSession()is the only method of a SessionFactory that you will use. The no-argument version will use the mechanism as described by the Configuration properties to connect to the database (usually the preferred mechanism).
Once you have obtained a session, you have access to a variety of options for manipulating data, as shown in Figure 6.2.

Generally speaking, the methods of a session are concerned with the traditional create, retrieve, update, and delete operations.
|
You'll want to wrap calls to the session using method beginTransaction() and then calling transaction.commit() when finished. Note that Hibernate will sometimes not actually flush SQL statements to the transaction until after the transaction is committed, which can on occasion lead to unwanted reordering of the SQL execution. For more information on flushing statements as part of a transaction, see Chapter 9.

In other words, Hibernate may not execute the SQL in the order in which you issue the commands in the session. To avoid this, use the session.flush() when executing statements to ensure the proper order of execution (see Chapter 9 for more information).
As shown in examples throughout this book, make sure that you are using try/catch/finally blocks to properly commit or roll back transactions as needed and that sessions are closed properly. |
Creating Objects
Creating objects in Hibernate is straightforward. Simply allocate the persistent objects using new, set the properties, and then use Session.save().
A complication may arise when you are creating objects with collections, however. The important thing to remember is that collection elements added to a parent where the collection is set to inverse="true" are not persisted automaticallyyou must manually save them and add them to the inverse="false" end of the relationship to persist them.
Unfortunately, Hibernate does not allow both sides of a collection to be set to inverse="false". This means that you must think carefully about your needs in order to decide which side of an association to map as inverse="false". To complicate matters somewhat, this is also true when objects are deletedit's easy to manually delete the associations, as long as the proper side of the relationship is used. You can work around this when working with the "wrong end" of a bi-directional association by using the outer-join-as-inverse-of-inner technique described in Chapter 8.
Session methods that are useful when you are saving objects are shown in Table 6.7.
Table 6.7. Object Creationsave(Object object) | Saves the object, and sets the id to the generated identifier. | save(Object object, Serializable id) | Saves the object using the specified identifier. Useful if you use an alternative mechanism for managing identifiers (for example, if you are relying on your EJB container for identifiers). | saveOrUpdate(Object object) | Will save the object if no identifier is present, or update the object if the identifier is valid. | saveOrUpdateCopy (Object object) | Will generate a new object either way, and will make a copy of the object from the current version if one already exists. | saveOrUpdateCopy(Object object, Serializable id) | Will generate a new object with the specified identifier either way, and will make a copy of the object from the current version if one already exists. |
Finding Objects
Hibernate offers a wide variety of options for retrieving objects from the database, including HQL, the Criteria API, and using SQL directly (or even mixing different strategies). For more information, see Chapter 8.
The various methods available for retrieving objects via HQL (as described in Chapter 8) are shown in Table 6.8. These methods are routinely expected to return no results (for example, a query for the number of students in a class may legitimately return no students if there are none enrolled). If you wish to view the inability to retrieve an object as an application failure use load(), described under Refreshing Objects below, instead of get().
Table 6.8. Finding Objects via HQLcreateQuery(String) | Use to retrieve a Query object based on an HQL query. | find(String) | Returns a java.util.List containing the results of the HQL query. | find(String query, Object[] values, Type[] types) | Returns a java.util.List, using the values and types provided as bound parameters. | find(String query, Object value, Type type) | Returns a java.util.List, using the value and type provided as a bound parameter. | get(Class, Serializable) | Retrieves a single persistent object, or null if not present. | get(Class, Serializable, LockMode) | Retrieves a single persistent object with the specified lock mode. Not normally necessaryHibernate manages lock modes automatically. | getNamedQuery(String) | Gets a query based on a query specified in the *.hbm.xml mapping file. | iterate(String) | Executes the query, returning the results lazily, loading each object with a new SELECT statement. | iterate(String query, Object[] values, Type[] types) | Executes the query, returning the results lazily, loading each object with a new SELECT statement. Values and types are used to set bound parameters. | iterate(String query, Object value, Type type) | Executes the query, returning the results lazily, loading each object with a new SELECT statement. Value and type are used to set a bound parameter. |
Some of these methods return a net.sf.hibernate.Query object instead of an immediate set of results. The net.sf.hibernate.Query object can be used to bind parameters and configure other aspects of the query before execution. The advantages of using an intermediate Query object include:
Selecting a portion of the results (using setMaxResults() and set-FirstResult()) Required to use named query parameters Retrieve the results as ScrollableResults
You may notice that there are two seemingly similar methods for retrieving results: find() and iterate(). The find() method executes immediately, whereas iterator() executes on demand. Therefore, find() methods typically perform better than iterator() methods. If you fear you may retrieve too many results with find(), you would probably be better off using create-Query() to configure the returned results.
|
Technically, the iterate() method returns only the object identifiers and a proxy, whereas the find() method performs a full retrieval. Thus the one time an iterate() could outperform a find() is if you are only interested in the returned primary keys, not the full objects. |
In addition to HQL, Chapter 8 describes the use of both the Hibernate Criteria API and raw SQL to access data. Table 6.9 shows these methods.
Table 6.9. Finding Objects via Criteria and SQLcreateCriteria(Class) | Pass in a persistent class to use as the base of the criteria, and then use additional methods to modify the query, as shown in Chapter 8. | createSQLQuery(String sql, String[] returnAliases, Class[] returnClasses) | Use to execute a query with multiple alias and classes, as shown in Chapter 8. | createSQLQuery(String sql, String returnAlias, Class returnClass) | Use to execute a query with a single alias and class, as shown in Chapter 8. |
Refreshing Objects
Sometimes, you know that an object exists, but only have part of the object's information. The most typical example would be a situation in which you know an object's identify reference but don't have the rest of the object information (this is shown in the sample application in Chapter 2). Given an identifier, the load() method can be used to retrieve the rest of the information about an object. The difference between a load() and a get() is that a load() will fail with an exception if the object is not found, whereas a get() will simply return null.
Within the context of a single session, you may expect that the mere act of updating or saving the object will modify the properties. For example, a trigger may modify the data written to a particular column when a record is saved. The refresh() method is used in the context of a single Session to retrieve these changes. In practice, you'll probably use the load() method much more frequently than the refresh() method. The refresh() method can also be used to reassociate objects across transactions with a session (converting a transient object to a persistent object). This is especially important if you wish to take advantage of cascading operations, because Hibernate may not recognize cascading associations if objects are not properly refreshed. For an example of this, see Listing 2.17, Deleting an Author.
Table 6.10. Obtaining the Current Dataload(Class clazz, Serializable id) | Use to load an object at any time, given only an identifier. | load(Object object, Serializable id) | As load, with a specific identifier. | load(Class clazz, Serializable id, LockMode lockMode) | As load, with a specific identifier and lock mode. | refresh(Object object) | Only usable if the object has already been loaded by this session. | refresh(Object obj, LockMode lockMode) | Only usable if the object has already been loaded by this session |
Deleting Objects
Deleting an object is largely a simple matter of passing the object to the session.delete(). You can use HQL to identify a range of records for higher-performance bulk deletes.
Table 6.11. shows the methods available for deleting data.
Table 6.11. Deleting Datadelete(Object object) | Removes a persistent instance from the database. | delete(String query) | Deletes all objects returned by the HQL query. | delete(String query, Object[] values, Type[] types) | Deletes all objects returned by the HQL query. | delete(String query, Object value, Type type) | Deletes all objects returned by the HQL query. |
Updating Objects
Much like creating an object, updating an object is a matter of simply modifying a persistent object and passing it to Session.update(). Table 6.12 shows the methods available for updating data.
Table 6.12. Deleting Dataupdate(Object object) | Updates the persistent instance with the identifier of the given transient instance. | update(Object object, Serializable id) | Updates the persistent instance with the identifier as specified. Particularly useful if using EJB to manage identity. |
 |