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
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.
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.
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 |
---|---|
|
Declares the class as an entity |
|
Specifies details of the table such as name and schema |
|
Specfies a query using a static name |
|
Primary key of the entity |
|
Specifies the generation strategy for the value of the primary key, |
|
Specifies that the attribute is mapped to a column in the table, |
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.
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.
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.
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
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.