Hibernate Basics for Java Persistence
As a Java persistence framework, Hibernate must work with multiple databases and within various application environments. Supporting these variations requires Hibernate to be highly configurable. After all, running a standalone application can be quite different from running a Web application. For instance, the differences in obtaining database connections can be significant.
Hibernate is typically configured in two steps.
- Configure the Hibernate service. This includes database connection parameters, caching, and the collection of persistent classes managed by Hibernate.
- Provide Hibernate with information about the classes to be persisted. Persistent class configuration allows you to bridge gaps between the class and databases.
Although it's commonly used within J2EE (Java EE) application servers such as WebSphere and JBoss, Hibernate can also be used in standalone applications. Hibernate can be configured to adapt to different environments, whose requirements vary. Hibernate works with various support services such as connection pools, caching services, and transaction managers. It allows you to maintain additional support services as well by implementing simple interfaces.
Individual persistent classes are also highly configurable. Each class may have a different method to generate identifier values, and you can persist complex object hierarchies. You can also customize specific object properties mapping to a SQL type, depending on the data types available in the database. There is much more to configuring persistent classes, as we'll discuss in this article.
What You'll Learn About Hibernate
In this article, we'll cover configuring Hibernate at the framework and persistent class level. More specifically, we'll discuss the following:
- Creating a basic hibernate.cfg.xml file
- Building mapping definition files to provide Hibernate with information about persistent classes
- The primary Hibernate classes used to persist and retrieve classes
- Advanced Hibernate configuration, including object caching and transaction management
- Persisting class hierarchies (inheritance) with Hibernate
This chapter requires that you've completed these steps:
- Ant, Hibernate, and MySQL are installed correctly.
- Download this basic project.
- Have basic knowledge of XML for the configuration file and mapping documents.
Hibernate must peacefully coexist in various deployment environments, from application servers to standalone applications. We refer to these as managed and nonmanaged environments, respectively. An application server is an example of a managed environment, providing services to hosted applications like connection pools and transaction management. Two of the commonly used application servers include WebSphere and JBoss.
The alternative is a nonmanaged environment, in which the application provides any required services. Nonmanaged environments typically lack the convenience services found in managed environments. A standalone Swing or SWT application is an example of a nonmanaged environment.
Hibernate supports a number of different configuration methods and options to support these scenarios. Configuring all of Hibernate's properties can be overwhelming, so we'll start slowly. Before we jump into configuration, look at figure 1, which shows the major Hibernate classes and configuration files.
The light gray boxes in the figure are the classes your application code will use most often. The dark gray boxes are the configuration files used by the Configuration class to create the SessionFactory , which in turn creates the Session instances. Session instances are your primary interface to the Hibernate persistence service.
Let's begin with the basic configuration that can be used in any Hibernate deployment. We'll discuss advanced configuration later in this article.
Figure 1. Primary Hibernate Components
Basic Hibernate Configuration
Hibernate provides two alternative configuration files: a standard Java properties file called hibernate.properties and an XML formatted file called hibernate.cfg.xml. We'll use the XML configuration file throughout this book, but it's important to realize that both configuration files perform the same function: configuring the Hibernate service. If both the hibernate.properties and hibernate.cfg.xml files are found in the application classpath, then hibernate.cfg.xml overrides the settings found in the hibernate.properties file. (Actually, we use both files in the example source code to avoid putting the database connection informationtion throughout the project directory tree.)
Before configuring Hibernate, you should first determine how the service obtains database connections. Database connections may be provided by the Hibernate framework or from a JNDI DataSource. A third method, user-provided JDBC connections, is also available, but it's rarely used.
Using Hibernate-managed JDBC Connections
The sample configuration file in listing 1 uses Hibernate-managed JDBC connections. You would typically encounter this configuration in a nonmanaged environment, such as a standalone application.
Listing 1. Example hibernate.cfg.xml file
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
To use Hibernate-provided JDBC connections, the configuration file requires the following five properties:
- connection.driver_class -The JDBC connection class for the specific database
- connection.url -The full JDBC URL to the database
- connection.username -The username used to connect to the database
- connection.password -The password used to authenticate the username
- dialect -The name of the SQL dialect for the database
The connection properties are common to any Java developer who has worked with JDBC in the past. Since you're not specifying a connection pool, which we cover later in this chapter, Hibernate uses its own rudimentary connection-pooling mechanism. The internal pool is fine for basic testing, but you shouldn't use it in production.
The dialect property tells Hibernate which SQL dialect to use for certain operations. Although not strictly required, it should be used to ensure Hibernate Query Language (HQL) statements are correctly converted into the proper SQL dialect for the underlying database.
The dialect property tells the framework whether the given database supports identity columns, altering relational tables, and unique indexes, among other database-specific details. Hibernate ships with more than 20 SQL dialects, supporting each of the major database vendors, including Oracle, DB2, MySQL, and PostgreSQL.
Hibernate also needs to know the location and names of the mapping files describing the persistent classes. The mapping element provides the name of each mapping file as well as its location relative to the application classpath. There are different methods of configuring the location of the mapping file, which we'll examine later.
Using a JNDI DataSource
To use Hibernate with database connections provided by a JNDI DataSource, you need to make a few changes to the configuration file, as shown in listing 2.
Listing 2. Modified hibernate.cfg.xml file
You would typically use this type of configuration when using Hibernate with an application server. The connection.datasource property must have the same value as the JNDI DataSource name used in the application server configuration. The dialect property serves the same purpose as the previous configuration file example.
At this point, you have almost enough information to configure Hibernate. The next step is to create mapping definitions for the objects you intend to persist.
Creating Hibernate Mapping Definitions
Mapping definitions, also called mapping documents, are used to provided Hibernate with information to persist objects to a relational database. The mapping files also provide support features, such as creating the database schema from a collection of mapping files.
Mapping definitions for persistent objects may be stored together in a single mapping file. Alternatively, the definition for each object can be stored in an individual mapping file. The latter approach is preferred, since storing the definitions for a large number of persistent classes in one mapping file can be cumbersome. We use the file-per-class method to organize our mapping documents throughout this book.
There is another advantage to having multiple mapping files: If you have all mapping definitions in a single file, it may be hard to debug and isolate any error to a specific class definition.
The naming convention for mapping files is to use the name of the persistent class with the hbm.xml extension. The mapping file for the Event class is thus Event.hbm.xml. The Event.hbm.xml file is shown in listing 3.
Listing 3 The Event.hbm.xml mapping file
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
Let's examine this mapping file in detail. The mapping definition starts with the hibernate-mapping element. The package attribute sets the default package for unqualified class names in the mapping. With this attribute set, you need only give the class name for other persistent classes listed in the mapping file, such as the Speaker and Attendee classes. To refer to a persistent class outside the given package, you must provide the fully qualified class name within the mapping document.
If Hibernate has trouble locating a class because of a missing package on, for instance, a many-to-one element, Hibernate throws a MappingException. This doesn't mean that Hibernate can't find the actual class file, but that it isn't able to navigate from one mapping definition to another.
Immediately after the hibernate-mapping tag, you encounter the class tag. The class tag begins the mapping definition for a specific persistent class. The table attribute names the relational table used to store the state of the object. The class element has a number of attributes available, altering how Hibernate persists instances of the class.