Java persistence with JPA and Hibernate, Part 1: Entities and relationships

Modeling entities and relationships for Java data persistence

1 2 3 4 Page 2
Page 2 of 4

JPA with Hibernate

In this section we move past concepts and start writing code that persists data to and from a relational database using JPA with Hibernate. We'll start by configuring an example application to use Hibernate as the JPA provider, then we'll quickly configure the EntityManager and write two classes that we want to persist to the database: Book and Author. Finally, we'll write a simple application that pulls together all of the application components and successfully persists our two entities to the database.

In this section you'll learn how to:

  • Configure a Java application to use Hibernate as your JPA provider.
  • Configure JPA's EntityManager in a persistence.xml file.
  • Create a simple JPA domain model representing two classes with a one-to-many relationship.
  • Use repositories to cleanly separate persistence logic from your application code.
  • Write, build, and run the example application using JPA to connect with a relational database.

You'll also get started with JPA Query Language (JPQL) and use it to execute a few simple database operations on the example application.

download
Download source code for the example application in this tutorial. Created for JavaWorld by Steven Haines.

Configuring Hibernate

To keep things simple, we're going to use the embedded H2 database for both development and runtime examples. You can change the JDBC URL in the persistence.xml file to point to any database you wish.

Start by reviewing the Maven POM file for the project, shown in Listing 1.

Listing 1. pom.xml


<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.geekcap.javaworld</groupId>
    <artifactId>jpa-example</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>jpa-example</name>
    <url>http://maven.apache.org</url>
    <properties>
        <java.version>1.8</java.version>
        <hibernate.version>5.3.6.Final</hibernate.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.geekcap.javaworld.jpa.JpaExample</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>install</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.2.Final</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.197</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</project>

We'll build this project using Java 8 and Hibernate version 5.3.6. Final, which is the latest version as of this writing. Plug-ins in the build node will set the Java compilation version, make the resultant JAR file executable, and ensure that all dependencies are copied to a lib folder, so that the executable JAR can run. We include four dependencies:

  • hibernate-core: Hibernate's core functionality.
  • hibernate-entitymanager: Hibernate's support for an EntityManager.
  • hibernate-jpa-2.1-api: The JPA API.
  • h2: The embedded H2 database. Note that its scope is set to runtime so that we can use it when we run our code.

Configuring the EntityManager

Recall that JPA's EntityManager is driven by the persistence.xml file. Listing 2 shows the contents of this file.

Listing 2. EntityManager config in persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="Books" transaction-type="RESOURCE_LOCAL">
        <!-- Persistence provider -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <!-- Entity classes -->
        <class>com.geekcap.javaworld.jpa.model.Book</class>
        <class>com.geekcap.javaworld.jpa.model.Author</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
            <property name="javax.persistence.jdbc.url"    value="jdbc:h2:mem:bookstore" />
            <property name="javax.persistence.jdbc.user" value="sa" />
            <property name="javax.persistence.jdbc.password" value="" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="show_sql" value="true"/>
            <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

The persistence.xml file begins with a persistence node that can contain one or more persistence-units. A persistence-unit has a name, which we'll use later when we create the EntityManager, and it defines the attributes of that unit. In this case, we configure properties in this unit to do the following:

  • Specify HibernatePersistenceProvider, so the application knows we're using Hibernate as our JPA provider.
  • Define two entities: a Book class and an Author class.
  • Define the database configuration via JDBC. In this case, we're using an in-memory H2 instance.
  • Configure Hibernate, including setting the Hibernate dialect to H2Dialect, so that Hibernate knows how to communicate with the H2 database.

The domain model

For this application, we're modeling a Book class and an Author class. These entities have a one-to-many relationship, meaning that a book can only be written by a single author, but an author can write many books. This domain model is shown in Figure 1.

osjp jpahibernate p1 fig1 Steven Haines

Figure 1. Domain model for a JPA/Hibernate application with two entities

Note: When we talk about database tables we typically speak about a "data model," but when we talk about Java entities and their relationships we typically refer to it as a "domain model."

Modeling the Book class

Let's begin with our entities. Listing 3 shows the source code for the Book class.

Listing 3. Book.java

package com.geekcap.javaworld.jpa.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table(name = "BOOK")
@NamedQueries({
        @NamedQuery(name = "Book.findByName",
                query = "SELECT b FROM Book b WHERE b.name = :name"),
        @NamedQuery(name = "Book.findAll",
                query = "SELECT b FROM Book b")
})
public class Book {
    @Id
    @GeneratedValue
    private Integer id;
    private String name;
    @ManyToOne
    @JoinColumn(name="AUTHOR_ID")
    private Author author;
    public Book() {
    }
    public Book(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    public Book(String name) {
        this.name = name;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Author getAuthor() {
        return author;
    }
    public void setAuthor(Author author) {
        this.author = author;
    }
    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", author=" + author.getName() +
                '}';
    }
}

The Book class is a simple POJO (plain old Java object) that manages three properties:

  • id: The primary key, or identifier, of the book.
  • name: The name, or title, of the book.
  • author: The author who wrote the book.

The class itself is annotated with three annotations:

  • @Entity: Identifies the Book as a JPA entity.
  • @Table: Overrides the name of the table to which this entity will be persisted. In this case we define the table name as BOOK.
  • @NamedQueries: Allows you to define JPA Query Language queries that can later be retrieved and executed by the EntityManager.

The Book's id attribute is annotated with both the @Id and @GeneratedValue. The @Id annotation identifies the id as the primary key of the Book, which will resolve to the primary key of the underlying database. The @GeneratedValue annotation tells JPA that the database should generate the primary key when the entity is persisted to the database. Because we have not specified a @Column annotation, the id will be mapped to the same column name, "id."

The Book's name attribute will be mapped to the "name" column in the BOOK table.

1 2 3 4 Page 2
Page 2 of 4
  
Shop Tech Products at Amazon