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 Performance
s.
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:
- One-to-many: Lazy
- Many-to-one: Eager
- Many-to-many: Lazy
- 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:
- What is JDBC? Introduction to Java Database Connectivity: An overview and guide to connecting to a database, handling SQL queries, and more with JDBC.
- Java persistence with JPA and Hibernate, Part 1: Modeling entities and relationships.
- Java persistence with JPA and Hibernate, Part 2: Many-to-many relationships and inheritance relationships.
- Should you use JPA for your next project?: Key questions that could help you decide.
This story, "What is JPA? Introduction to Java persistence" was originally published by JavaWorld.