Accessing data using Java Persistence API

Note
This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website.

Learn how to map Java Objects to database tables and perform CRUD operations using JPA

What you’ll learn

You will learn how to use the Java Persistence API (JPA) to map Java objects to database tables. JPA is a standard for Object Relational Mapping (ORM) and eliminates the burden of having to write SQL code when performing database operations.

The application that you will be working with is the Event Manager, which provides services for creating, retrieving, updating and deleting Event objects. The application uses an Embedded Derby database as a datastore for all the Event objects. If you want to learn more about Embedded Derby, you can do so from the official website.

You will use JPA annotations to define a Plain Old Java Object (POJO) class as an entity class whose persistent fields are persisted to the datastore. Every entity object has a lifecycle that consists of different states that are managed by an EntityManager. In this application the EntityManager is container-managed so the EJB container is responsible for transaction boundaries as well as the opening and closing of the EntityManager. A container-managed EntityManager requires the use of the Java Transaction API (JTA). By using JTA transactions, the Event Manager application does not have to pass references to EntityManager instances from one component to another.

Getting started

Try what you’ll build

Point your browser to the http://localhost:9080/eventmanager.jsf URL. As you can see, the event application currently has no events stored in the database. Go ahead and click on the Create Event button located in the left navigation bar. After entering an event name, location and time, click on Submit to persist your event entity to the database. The event is now stored in the database and is visible in the list of current events. The Update button located beside each event allows you to make modifications to the persisted entity and the Delete button allows you to remove entities from the database.

Defining a JPA entity class

Navigate to the start directory to begin.

Before being able to use JPA to store Java objects in a database, an entity class must be defined. A JPA entity is a Java object whose non-transient fields will be persisted to the database. Any POJO class can be designated as a JPA entity. However, the class must be annotated with the @Entity annotation, must not be declared final and must have a public or protected non-argument constructor. JPA uses a database table for every entity and persisted instances will be represented as one row in the table.

Add the following JPA annotations to the Event class in the src/main/java/io/openliberty/guides/jpaguide/models/Event.java file:

link:finish/src/main/java/io/openliberty/guides/jpaguide/models/Event.java[role=include]

Let’s break down the new annotations:

Annotation Description

@Entity

Declares the class as an entity

@Table

Specifies details of the table such as name and schema

@NamedQuery

Specfies a query using a static name

@Id

Primary key of the entity

@GeneratedValue

Specifies the generation strategy for the value of the primary key, strategy = GenerationType.AUTO indicates that the persistence provider will pick a strategy depending on the database used

@Column

Specifies that the attribute is mapped to a column in the table, name is optional and indicates the name of the column in the table

Accessing data using JPA

Before being able to access data using JPA, a connection to the database must be established. An EntityManager provides the functionality for performing operations on the database such as persisting, loading, updating and deleting entities. The EntityManager’s configuration is defined by a persistence unit specified in the persistence.xml file.

Create the src/main/resources/META-INF/persistence.xml file:

link:finish/src/main/resources/META-INF/persistence.xml[role=include]

The persistence unit is defined by the <persistence-unit name="jpa-unit" transaction-type="JTA"></persistence-unit> XML element. The name attribute is required and is used to identify the persistent unit. The transaction-type=”JTA” element specifies to use managed (JTA) transaction management. In a Java EE environment, the default is JTA if this element is not specified.

A transaction type of JTA requires for a JTA data source to be provided. This is done via the <jta-data-source>jdbc/samplejpadatasource</jta-data-source> element which specifies the Java Naming and Directory Interface (JNDI) name of the data source that is to be used by the container. This means that a JDBC connection does not have to be specified in the persistence.xml file and instead the JTA data source can be preconfigured.

Create the src/main/liberty/config/server.xml file:

link:finish/src/main/liberty/config/server.xml[role=include]

A shared library is defined by the <library id="derbyJDBCLib"></library> element. This element points to the directory of the JDBC driver. The JDBC driver is what enables the application to interact with the database.

The data source configuration is done within the <dataSource id="samplejpadatasource jndiName="jdbc/samplejpadatasource"></dataSource> element. The jndiName="jdbc/samplejpadatasource" attribute provides a JNDI name for the data source so that it can be looked up by a component.

The data source configuration also contains properties such as the database name and whether to create the database if it does not already exist. These properties can vary based on the database that is being used.

Performing CRUD operations using JPA

CRUD is an abbreviation that defines the four basic functionalities that can be performed on a database: create, read, update and delete.

Create the src/main/java/io/openliberty/guides/jpaguide/dao/EventDao.java file:

link:finish/src/main/java/io/openliberty/guides/jpaguide/dao/EventDao.java[role=include]

Every entity object has a lifecycle that consists of four states: new, managed, removed and detached. Whenever a new Event object is created its state will be new, meaning that it is not mapped to a row in the database table and is not associated with an EntityManger.

The EntityManager manages the lifecycle of entity instances. Every EntityManager instance is associated with a persistence context. The persistance context manages a set of entities and is aware of the different states that an entity can have. Since the container is responsible for transaction boundaries, we do not need to explicitly begin, commit or rollback transactions. The EJB container will ensure that the required methods are executed within the boundaries of an active transaction. In order to use the EntityManager at runtime, we must inject it into our EJB component via the @PersistenceContext annotation.

The createEvent method persists an instance of the Event entity class to the database. By calling the persist method on an EntityManager, it changes the event objects instance from new to managed. This means that the entity is now mapped to a row in the database table and is being managed by the EntityManager.

The readEvent method retrieves Event objects from the database. Entity objects are retrieved via the find method which requires both the entity class and the primary key of the object. If the EntityManager already manages the searched object in its persistence context, then no retrieval from the database is required since the managed Event object will be returned as is. But, if the EntityManager does not already manage the object in its persistence context, a new entity object will be constructed with data retrieved from the database and returned in a managed state. If the Event object is not found in the database, Null is returned.

The updateEvent method updates an Event object in the database. The EntityManager automatically tracks all managed entity objects in its persistence context for changes and synchronizes them with the database. The merge method will create a new instance of the entity object and make that new instance managed. But, the entity object passed into the merge method is no longer managed.

The deleteEvent method deletes an Event object from the database. By calling the remove method on an EntityManager, the managed entity will be removed from the database and the entity objects state becomes removed.

Note that when an entity is no longer associated with a persistence context, its changes will no longer be managed by the EntityManager and the entity becomes detached.

Building and running the application

When the server is running, visit the http://localhost:9080/eventmanager.jsf URL to view the Event Manager application.

Using the Create event button in the left navigation bar you are able to create events that will be persisted to the database. Once you have created an event, it will be available to view, update and delete in the Event list section.

Testing the application

Create the EventAppTest test class in the finish/src/test/java/it/io/openliberty/guides/jpaguide/tests/EventAppTest.java file:

link:finish/src/test/java/it/io/openliberty/guides/jpaguide/tests/EventAppTest.java[role=include]

The testCreatingDeletingNewEvent method creates a test event and then gets a list of events from the http://localhost:9080/events URL to verify that the test event was actually persisted to the database. Next, the test event will be deleted from the database and the method will get a list of events from the http://localhost:9080/events URL once more. This time, when attempting to retrieve the test event, the return value will be Null since it was removed from the database.

The testUpdatingEvents method also creates a test event and then gets a list of events from the http://localhost:9080/events URL to verify that the test event was actually persisted to the database. Next, the method will update the test event with a new name, location and time. A list of events will be retrieved from the http://localhost:9080/events once again to verify that the event was successfully updated in the database. Lastly, the updated test event will be deleted from the database and the method will get a list of events from the http://localhost:9080/events URL one final time. As expected, when attempting to retrieve the test event, the return value will be Null since it was removed from the database.

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.jpaguide.tests.EventAppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.9 sec - in it.io.openliberty.guides.jpaguide.tests.EventAppTest

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Great work! You’re done!

You have learned how to map Java objects to database tables by defining a JPA entity class whose instances are represented as rows in the table.

You have have used a container-managed EntityManager to manage entity instances and their lifecycles. You injected the EntityManager into an EJB component and performed basic CRUD operations on the database using JPA.