What is JPA? Introduction to the Jakarta Persistence API

Get to know the Java ORM standard for storing, accessing, and managing Java objects in a relational or NoSQL database.

1 2 Page 2
Page 2 of 2

If the Musician included a Band field, the relationship between these entities could be many-to-one, implying a collection of Musicians on the single Band class. (Assuming each musician only performs in a single band.)

If Musician included a BandMates field, that could represent a many-to-many relationship with other Musician entities.

Finally, Musician might have a one-to-one relationship with a Quote entity, used to represent a famous quote: Quote famousQuote = new Quote().

Defining relationship types

JPA has annotations for each of of its relationship mapping types. Listing 7 shows how you might annotate the one-to-many relationship between Musician and Performances.

Listing 7. Annotating a one-to-many relationship


public class Musician {
  @OneToMany
  @JoinColumn(name="musicianId")
  private List performances = new ArrayList();
  //...
}

One thing to notice is that the @JoinColumn tells JPA what column on the Performance table will map to the Musician entity. Each performance will be associated to a single Musician, which is tracked by this column. When JPA loads a Musician or a Performance into the database, it will use this information to reconstitute the object graph.

Entity states and detached entities

An entity is the general name for an object whose persistence is mapped with ORM. The entities in your running application will always be in one of four states: transient, managed, detached, and removed.

One situation you’ll encounter in JPA is that of a detached entity. This simply means that the objects you are dealing with have departed from what is in the datastore backing them, and the session that backs them has been closed. In other words, JPA wants to keep the objects up-to-date, but it’s unable to. You can reattach a detached entity by calling entityManager.merge() on the entity.

Any object that is not persistent is transient. The object is only a potential entity at that point.  Once entityManager.persist() is called on it, it becomes a persistent entity.

A managed object is a persistent entity.

When an entity has been deleted from the datastore, but still exists as a live object, it is said to be in the removed state.

Vlad Mihalcea has written a fine discussion of entity states, along with the subtle differences between JPA’s EntityManager and Hibernate’s Session classes for managing them.

What is EntityManager.flush() for?

Many developers new to JPA wonder about the purpose of the EntityManager.flush() method. The JPA manager will cache the operations required to keep the persisted state of the entities consistent with the database, and batch them for efficiency. 

Sometimes, though, you will need to manually cause the JPA framework to enact the operations required to push the entities to the database. This could be to cause a database trigger to execute, for example. In that case, you can use the flush() method, and all entity state that hasn’t been persisted will immediately be sent to the database.

Fetching strategies

In addition to knowing where to place related entities in the database, JPA needs to know how you want them loaded. Fetching strategies tell JPA how to load related entities. When loading and saving objects, a JPA framework must provide the ability to finetune how object graphs are handled. For instance, if the Musician class has a bandMate field (as shown in Listing 7), loading george could cause the entire Musician table to be loaded from the database!

You need to be able to define lazy loading of related entities–recognizing, of course, that relationships in JPA can be eager or lazy. You can use annotations to customize your fetching strategies, but JPA's default configuration often works out of the box, without changes:

  1. One-to-many: Lazy
  2. Many-to-one: Eager
  3. Many-to-many: Lazy
  4. One-to-one: Eager

JPA installation and setup

We'll conclude with a quick look at installing and setting up JPA for your Java applications. For this demonstration I'll use EclipseLink, the JPA reference implementation.

The common way to install JPA is to include a JPA provider into your project. Listing 8 shows how you would include EclipseLink as a dependency in your Maven pom.xml file.

Listing 8. Include EclipseLink as a Maven dependency


<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>4.0.0-M3</version>
</dependency>

You will also need to include the driver for your database, as shown in Listing 9.

Listing 9. Maven dependency for a MySql connector


<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

Next, you'll need to tell the system about your database and provider. This is done in the persistence.xml file, as shown in Listing 10.

Listing 10. Persistence.xml


http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
      <persistence-unit name="MyUnit" transaction-type="RESOURCE_LOCAL">
           <properties>
                        <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/foo_bar"/>
                        <property name="jakarta.persistence.jdbc.user" value=""/>
                        <property name="jakarta.persistence.jdbc.password" value=""/>
                        <property name="jakarta.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
           </properties>
      </persistence-unit>
</persistence>

There are other ways to provide this information to the system, including programmatically. I recommend using the persistence.xml file because storing dependencies this way makes it very easy to update your application without modifying code.

Spring configuration for JPA

Using Spring will greatly ease the integration of JPA into your application. As an example, placing the @SpringBootApplication annotation in your application header instructs Spring to automatically scan for classes and inject the EntityManager as required, based on the configuration you've specified.

Listing 11 shows the dependencies to include if you want Spring's JPA support for your application.

Listing 11. Adding Spring JPA support in Maven


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.6.7</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.6.7</version>
</dependency>

When to use JPA

The question of whether to use JPA is a common source of analysis paralysis when designing a Java application. Especially when attempting to make up-front technology decisions, you don’t want to get data persistence—an essential and long-term factor—wrong.

To break this kind of paralysis, it’s useful to remember that applications can evolve into using JPA. You might build exploratory or prototype code using JDBC or a NoSQL library, then start adding in JPA. There’s no reason these solutions can’t coexist.

After being paralyzed by indecision, the next worst thing is to adopt JPA when the additional effort it implies will prevent a project from moving forward. JPA can be a win for overall system stability and maintainability, and those are wonderful goals for a more established project; however, sometimes simpler is better, especially at the beginning of a project.

If your team doesn't have the capacity to adopt JPA up front, consider putting it on your roadmap for the future.

Conclusion

Every application that deals with a database should define an application layer whose sole purpose is to isolate persistence code. As you've seen in this article, the Jakarta Persistence API introduces a range of capabilities and support for Java object persistence. Simple applications may not require all of JPA's capabilities, and in some cases the overhead of configuring the framework may not be merited. As an application grows, however, JPA's structure and encapsulation really earn their keep. Using JPA keeps your object code simple and provides a conventional framework for accessing data in Java applications.

Learn more about the Jakarta Persistence API and related technologies:

This story, "What is JPA? Introduction to the Jakarta Persistence API" was originally published by JavaWorld.

Copyright © 2022 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2
How to choose a low-code development platform