© Joseph B. Ottinger, Jeff Linwood and Dave Minter 2016

Joseph B. Ottinger, Jeff Linwood and Dave Minter, Beginning Hibernate, 10.1007/978-1-4842-2319-2_2

2. Integrating and Configuring Hibernate

Joseph B. Ottinger, Jeff Linwood2 and Dave Minter3

(1)Youngsville, North Carolina, USA

(2)Austin, Texas, USA

(3)London, UK

Integrating Hibernate into a Java application is easy. The designers of Hibernate avoided some of the more common pitfalls and problems with the existing Java persistence solutions, and created a clean but powerful architecture. In practice, this means that you do not have to run Hibernate inside any particular Java EE container or framework. As of Hibernate 5.2, Java 8 or later is required, thanks to the integration of the date and time API and other such useful features.1

At first, adding Hibernate to your Java project looks intimidating: the distribution includes a large set of libraries. To get your first Hibernate application to work, you have to set up the database references and the Hibernate configuration, which might include mapping your objects to the database. You also have to create your POJOs, including any annotation-based mapping. After you have done all of that, you need to write the logic in your application that uses Hibernate to actually accomplish something! But once you learn how to integrate Hibernate with your application, the basics apply for any project that uses Hibernate.

One of the key features of Hibernate’s design is the principle of least intrusiveness: the Hibernate developers did not want Hibernate to intrude into your application more than was necessary. This led to several of the architectural decisions made for Hibernate. In Chapter 1, you saw how Hibernate can be applied to solve persistence problems using conventional Java objects. In this chapter, we explain some of the configuration details needed to support this behavior.

The Steps Needed to Integrate and Configure Hibernate

This chapter explains configuration and integration in detail, but for a quick overview, refer to the following list to determine what you need to do to get your first Hibernate application up and running. Then Chapter 3 will lead you through the building of a pair of small example applications that use Hibernate. The first of these examples is as simple as we could make it, so it is an excellent introduction to the following necessary steps:

  1. Identify the POJOs that have a database representation.

  2. Identify which properties of those POJOs need to be persisted.

  3. Annotate each of the POJOs to map your Java object's properties to columns in a database table (covered in more detail in Chapter 6).

  4. Create the database schema using the schema export tool, use an existing database, or create your own database schema.

  5. Add the Hibernate Java libraries to your application’s classpath (covered in this chapter).

  6. Create a Hibernate XML configuration file that points to your database and your mapped classes (covered in this chapter).

  7. In your Java application, create a Hibernate Configuration object that references your XML configuration file (covered in this chapter).

  8. Also in your Java application, build a Hibernate SessionFactory object from the Configuration object (covered in this chapter).

  9. Retrieve the Hibernate Session objects from the SessionFactory, and write your data access logic for your application (create, retrieve, update, and delete).

Don’t worry if you don’t understand every term or concept mentioned in this list. After reading this chapter, and then following the example in the next chapter, you will know what these terms mean and how they fit together.

Understanding Where Hibernate Fits into Your Java Application

You can call Hibernate from your Java application directly, or you can access Hibernate through another framework. You can call Hibernate from a Swing application, a servlet, a portlet, a JSP page, or any other Java application that has access to a database. Typically, you would use Hibernate to either create a data access layer for an application or replace an existing data access layer.

Hibernate supports the Java Management Extensions (JMX) , J2EE Connector Architecture (JCA) , and Java Naming and Directory Interface (JNDI) Java language standards. Using JMX, you can configure Hibernate while it is running. Hibernate may be deployed as a JCA connector, and you can use JNDI to obtain a Hibernate session factory in your application. In addition, Hibernate uses standard Java Database Connectivity (JDBC) database drivers to access the relational database. Hibernate does not replace JDBC as a database connectivity layer; Hibernate sits on a level above JDBC.

In addition to the standard Java APIs, many Java web and application frameworks now integrate with Hibernate. Hibernate’s simple, clean API makes it easy for these frameworks to support Hibernate in one way or another. The Spring framework provides excellent Hibernate integration, including generic support for persistence objects, a generic set of persistence exceptions, and transaction management. Appendix C explains how Hibernate can be configured within a Spring application.

Regardless of the environment into which you are integrating Hibernate, certain requirements remain constant. You will need to define the configuration details that apply; these are then represented by a ServiceRegistry object. From the ServiceRegistry object, a SessionFactory object is created; and from this, Session objects are instantiated, through which your application accesses Hibernate’s representation of the database.

Deploying Hibernate

There are two sets of components necessary for integration of Hibernate into your application: a database driver and the Hibernate libraries themselves.

The example code for this book uses H2 as a small, embeddable database2; this can be found at http://h2database.com/ . This is not to indicate that other databases are of less value than H2, but it is simply an expedient choice; H2's sort-of sibling project HSQLDB is also workable, as is Derby; if you have a MySQL or PostgreSQL data server handy, those work as well, but an embedded database means that you don’t have to have an external process running, nor do you have to configure a special database or user account.3

If you're using the Hibernate binary download (from a “release bundle,” via http://www.hibernate.org/downloads ), all of the jars contained in the lib/required directory are mandatory in order to use Hibernate.

Perhaps an easier way to integrate Hibernate is through the use of a build tool, like Gradle ( http://www.gradle.org/ , used by the Hibernate project itself), SBT ( http://www.scala-sbt.org/ ), or Maven ( http://maven.apache.org/ ), the latter which is arguably the most popular of the build tools, if not the best.4

All of these build tools are able to bundle dependencies into a deliverable artifact. They're also able to include dependencies transitively, which means that projects that depend on a given subproject also inherit that subproject's dependencies.

We'll target Maven as a build environment for the rest of the book; users of other build tools are generally able to migrate from Maven fairly easily.5

Installing Maven

There are many ways to install Maven. This is a cursory overview; different operating systems (and different system configurations) can affect the installation procedure, so when you are in doubt, you can refer to http://maven.apache.org/download.cgi#Installation for the actual documentation.

To save you some time, however, you can download Maven from http://maven.apache.org/download.cgi/ ; you should get the most recent version. UNIX users (including Linux and MacOS users) should download the file ending in tar.gz; Windows users should download the zip file.

In UNIX , untar the file into a directory of your choice; an example of the command that might be run is this:

mkdir ∼/tools || cd ∼/tools; tar xf apache-maven-3.3.9-bin.tar.gz

This will create ∼/tools/apache-maven-3.3.9/, and the mvn executable will be in ∼/tools/apache-maven-3.3.9/bin; add this to your command path.

For Windows, open the archive and extract it into a known location (for example, C: ools). Add the location of mvn.bat (in this example, C: oolsapache-maven-3.3.9in) to your path via the System Properties dialog, and you should be able to run Maven with “mvn” in the command prompt.

Maven uses a project object model , typically written in XML, called “ pom.xml”. This file describes the project's name and versions and builds configurations (if any), as well as any subprojects and any project dependencies. When Maven is run, it will automatically download any resources it needs in order to complete the build as specified, and then it will compile the project source code; if the project includes tests, it will run the tests and complete the build if (and only if) no test failures occur.

This book uses a parent project that contains global dependencies for the book, and subprojects corresponding to the chapters; much of the operating code is written as a set of tests in the subprojects. Chapter 1, for example, used two methods to write data to and read data from a database; those tests were written as TestNG6 test classes: chapter01.hibernate.PersistenceTest and chapter01.jdbc.PersistenceTest.

The parent project's configuration file , after Chapter 1 was written, looked like Listing 2-1.

Listing 2-1. The Top-Level Project Object Model for Maven
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.autumncode.books.hibernate</groupId>
    <artifactId>hibernate-parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>chapter01</module>
    </modules>
    <name>hibernate-parent</name>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>[6.9.10,)</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>[5.0.0,5.9.9]</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.192</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <showDeprecation>true</showDeprecation>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

This specifies a number of things about the project (such as the Java version, which is the current maintained version of Java7), and includes three dependencies: Hibernate itself; the H2 database; and TestNG, the last which is limited to the testing phase (as the “scope” node instructs).

The child projects —in this listing, this is only chapter01—will receive this configuration and its set of dependencies automatically, which means we don't have to repeat ourselves very often.

To build and run this project after installing Maven, you simply have to go to the directory that contains pom.xml, and execute “mvn package” — that will, as stated, download all the required dependencies, build them, and then test the projects in order.

Maven projects have a specific folder layout, although it's configurable; by default, the Java compiler compiles all code found in src/main/java, and the resulting class files are included with src/main/resources in the deliverable artifact. The src/test/java directorycontains tests, which are then compiled and run (with src/test/resources and the deliverable artifact in the classpath as well).

Wow, that's a lot of non-Hibernate discussion – and all of it can be found (and subverted) on the websites for each given build environment. In general, you can (and should) use what you like; this book uses Maven because of how common it is, not because it's the One True Build Tool.

Let's look at the actual code we've been running so far and explain it all. That will give you a basis for future discussion, even if you're not going to use it much beyond this chapter.

We've already mentioned the top-level pom.xml file ; we're going to start in the chapter02 directory (which is a clone of the chapter01 directory, except with “chapter02” instead of “chapter01”). Our project description file (our pom.xml) is very simple, specifying only the parent project and the current project's name (see Listing 2-2).

Listing 2-2. Chapter 2’s Project Object Model
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>hibernate-parent</artifactId>
        <groupId>com.autumncode.books.hibernate</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>


    <artifactId>chapter02</artifactId>
</project>

Our Message.java is held in src/main/java/chapter02/Message.java. This is the same POJO as in Listing 1-5, except that it’s in a different package (chapter02.hibernate instead of chapter01.hibernate). Since everything else is the same, we won't list it here.

Our actual running code is in the src/test directory and consists of two relevant files:8 src/test/java/chapter02/hibernate/PersistenceTest.java and src/test/resources/hibernate.cfg.xml.

We've already seen the test methods from PersistenceTest.java, but let's take a look at the entire Listing 2-3 so you understand everything in it.

Listing 2-3. A Set of Persistence Tests
package chapter02.hibernate;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;


import java.util.List;

import static org.testng.Assert.assertEquals;

public class PersistenceTest {
    SessionFactory factory;


    @BeforeSuite
    public void setup() {
        StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                .configure()
                .build();
        factory = new MetadataSources(registry)
                .buildMetadata()
                .buildSessionFactory();
    }


    @Test
    public void saveMessage() {
        Message message = new Message("Hello, world");
        try (Session session = factory.openSession()) {
            Transaction tx = session.beginTransaction();
            session.persist(message);
            tx.commit();
        }
    }


    @Test(dependsOnMethods = "saveMessage")
    public void readMessage() {
        try (Session session = factory.openSession()) {
            List<Message> list = session.createQuery("from Message",
                Message.class).list();


            assertEquals(list.size(), 1);
            for (Message m : list) {
                System.out.println(m);
            }
        }
    }
}

Again, note that we're using TestNG to run the tests, which in this case affects our class in a few simple ways.

First, the actual test methods are annotated with @Test; we indicate a dependency between tests with a setting for readMessage(). If saveMessage() were to fail, readMessage() would not be executed, as its execution depends on a successful saveMessage().

Second, there's a @BeforeSuite method , which is executed before any of the tests are attempted. This gives us a chance to do system initialization. This is where we're setting up Hibernate for usable state – in the JDBC code, we use this same mechanism to load the JDBC driver and create our database schema.9

Third, we indicate that failure through the use of the statically imported assertEquals(),10 which should be easy to understand. An exception also indicates a failure, unless we tell TestNG that we expect an exception to be thrown (and we can also tell TestNG what specific types of exceptions allow the test to pass).

You're likely to use this construct often because it's easy to integrate into your project build life cycle (as Maven runs the available tests as part of the build). Also, it gives you a clear order of execution, and also provides an easy way to see what works and what doesn't work. You should feel free to write tests to validate your own understanding of what is being described.

Next, note how the test is constructed.

The test shows the canonically correct way to use Hibernate's native API:11 first, construct a SessionFactory, which is the entry point to the Hibernate API (much as EntityManager is the entry point for the Java Persistence Architecture); then use the SessionFactory to retrieve short-lived Session objects through which updates, or reads, are performed. We use automatic resource management to make sure the Session is closed when the block is finished executing.

We actually don’t (and can’t) use automatic resource management on the Transaction, though. We don’t want a “close” mechanism on a Transaction; we want to specifically determine the end result, whether it’s committed or not. An automatic management mechanism for transactions would have unfortunate implications in the cases of error conditions (which can be common in database-oriented applications.) We cover transactions a good bit more thoroughly in Chapter 8.

The actual tests mirror the JDBC code fairly well12 (or vice versa); in both, we acquire a resource through which we “talk to” the database, then we perform an action, then we commit our changes (if any) and clean up. (There are definitely details being skipped; this is the ten-thousand-foot view of the mechanisms in place.)

The last piece of the puzzle is the actual configuration file itself, which is in src/test/resource/hibernate.cfg.xml. See Listing 2-4.

Listing 2-4. The hibernate.cfg.xml, the Hibernate Configuration
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--  Database connection settings  -->
        <property name="connection.driver_class">org.h2.Driver</property>
        <property name="connection.url">jdbc:h2:./db2</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"/>
        <property name="dialect">org.hibernate.dialect.H2Dialect</property>
        <!--  Echo all executed SQL to stdout  -->
        <property name="show_sql">true</property>
        <!--  Drop and re-create the database schema on startup  -->
        <property name="hbm2ddl.auto">create-drop</property>
        <mapping class="chapter02.hibernate.Message"/>
    </session-factory>
</hibernate-configuration>

This file might serve as a boilerplate for every Hibernate configuration. In it, we specify the JDBC driver class; the JDBC URL, user name, and password used to access the database; a dialect(which allows Hibernate to correctly produce SQL for each given database); some configuration, such as whether to dump the generated SQL to the console; and what to do for the schema. Lastly, it specifies the classes that should be managed — in this case, only our Message class.

There are a lot of things we can control from this file; we can even use it to specify the mapping of our objects to the database (i.e., ignoring the annotations we've been using so far). You'll see a little more of how to do this in later chapters of this book; it helps quite a bit in mapping existing database schemata13 to object models.

Most coders will (and should) prefer the annotation-based mappings.

Connection Pooling

As you’ve seen, Hibernate uses JDBC connections in order to interact with a database. Creating these connections is expensive — probably the most expensive single operation Hibernate will execute in a typical-use case.

Since JDBC connection management is so expensive, you can pool the connections, which can open connections ahead of time (and close them only when needed, as opposed to “when they’re no longer used”).

Thankfully, Hibernate is designed to use a connection pool by default, an internal implementation. However, Hibernate's built-in connection pooling isn't designed for production use. In production, you would use an external connection pool by using either a database connection provided by JNDI (the Java Naming and Directory Interface) or an external connection pool configured via parameters and classpath.

Note: C3P0 ( http://www.mchange.com/projects/c3p0/ ) is an example of an external connection pool. To use it, we would make two changes. First, we need to add c3p0 and Hibernate's c3p0 connection provider as dependencies in the pom.xml. Observe that the version of the hibernate-c3p0 dependency should match the Hibernate version. Listing 2-5 illustrates this connection.

Listing 2-5. Changes for the Object Model to Include c3p0
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>[5.0.0,5.9.9)</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
    </dependencies>

Next, we need to change the Hibernate configuration to tell it to use c3p0. To do this, all we need to do is add any c3p0 configuration property to hibernate.cfg.xml. For example:

       <property name="c3p0.timeout">10</property>

With this line in the configuration, Hibernate will disable its internal connection pool and use c3p0 instead.

However, c3p0 is not the only connection pool; there's also Proxool ( http://proxool.sourceforge.net/ ), which gets mentioned often in the Hibernate documentation.

If you're using Hibernate in a Java EE context – in a web application, for example – then you'll want to configure Hibernate to use JNDI. JNDI connection pools are managed by the container (and thus controlled by the deployer), which is generally the “right way” to manage resources in a distributed environment.

For example, WildFly ( http://wildfly.org/ ) comes preinstalled with an example datasource, named (helpfully) “java:jboss/datasources/ExampleDS.” It's an H2 database, so the dialect is already correct; the new configuration would look something like what is shown in Listing 2-6.

Listing 2-6. Hibernate, Configured to Use JNDI as a Datasource
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--  Database connection settings  -->
        <property name="jndi.url">java:jboss/datasources/ExampleDS</property>
        <property name="dialect">org.hibernate.dialect.H2Dialect</property>
        <!--  Echo all executed SQL to stdout  -->
        <property name="show_sql">true</property>
        <!--  Drop and re-create the database schema on startup  -->
        <property name="hbm2ddl.auto">create-drop</property>
        <mapping class="chapter02.hibernate.Message"/>
    </session-factory>
</hibernate-configuration>

Ideally, the java:jboss tree wouldn't be used; you'd use a name scoped to the application component, in the java:comp/env tree.14

Summary

In this chapter, we've presented a brief overview of how to use Maven to build and test your projects, as well as how to specify dependencies. We've also shown the usage of TestNG as a simple harness to run code. Lastly, we've explained how to configure Hibernate, starting from acquiring the SessionFactory and concluding with the SessionFactory's configuration, covering the simple JDBC connection management included with Hibernate, the use of a connection pool, and employment of JNDI to acquire database connections.

You should now have enough of a harness in place such that you can focus on using Hibernate to help you manage a persistent object model. We will add more detail on this as needed in the example code.

In the next chapter, we're going to build some slightly more complex (and useful) object models to illustrate more of Hibernate's core concepts.

Footnotes

1 That means that if you’re on an older version of the JVM, you’ll have to stick to older versions of Hibernate. That shouldn’t be too much of a bother; Java 7 has been end-of-lifed since April of 2015. It’s time to move up if you haven’t already, thanks to security concerns and, of course, the fact that Java 8 is nice.

2 The prior edition of this book actually used HSQLDB. There was not a concrete reason for the switch, but research among the community showed a preference for H2 over HSQLDB, for various reasons (mostly centering on the fact that H2 is written by HSQL’s original author). Your authors listen to the people.

3 It’s also worth noting that there are plug-ins for Maven that can embed external databases like MariaDB (a variant of MySQL); see MariaDB4J at https://​github.​com/​vorburger/​MariaDB4j if you’re interested. But H2 is smaller and faster for our purposes, and since Hibernate is database independent, the actual database you use should largely be irrelevant.

4 Arguments about “which build tool is best” are a lot like arguments about relative merits of IDEA, Emacs, Netbeans, Eclipse, and others. Everyone has an opinion, and that opinion is perfectly valid for the one who holds it; however, Maven is generally agreed upon not to be the “best build tool,” much like Eclipse is not the “best editor.” They're popular. They're common. That's about it.

5 If you don’t use a build tool, please see your IDE’s instructions for adding libraries to projects. However, it’s worth noting that using a build tool is wise; it means that your builds are easily duplicated. For example, if you want to show your code to someone else, without a build tool you will have to make sure their environment matches yours; but with a build tool, all you have to do is make sure they have the tool installed. You can see this in this book; I describe the build with Maven, and readers can use any editor or IDE they like without affecting the content whatsoever.

6 TestNG ( http://testng.org/ ) is a unit testing framework. It’s a popular alternative to JUnit ( http://junit.org ), and has some rather desirable features by comparison.

7 Java 7 was end-of-lifed in April of 2015. It’s time to move on if you’re able to do so. See https://java.com/en/download/faq/java_7.xml for details.

8 There are other classes in the tree, but we no longer care about JDBC in this chapter; they're here because you were promised that chapter02's tree was the same as chapter01's. All of the JDBC stuff is going to be ignored.

9 Hmm, we promised that we weren't going to mention the JDBC code any more. Whoops.

10 Importing the assertEquals() statically means that it can be called directly without a reference to the org.testng.Assert class. Static imports normally aren’t a very good thing, but this is an idiomatic and very useful example of them.

11 Hibernate implements the Java Persistence Architecture as an alternative API. It's a little more generic than the native API, and is configured slightly differently, even though most of the concepts are identical.

12 Darn it, we keep on coming across that JDBC code that isn’t supposed to be mentioned.

13 “Schemata” is the plural of “schema.” See http://​www.​merriam-webster.​com/​dictionary/​schema.

14 See http://www.ibm.com/developerworks/library/j-jndi/?ca=dnt-62 for an article that discusses this concept in some detail, although the implementation specifics are slightly dated.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset