Data persistence with the Jakarta Persistence API

The Jakarta Persistence API (JPA) simplifies data persistence and object relational mapping for Java applications. With JPA, applications can efficiently create, read, update, and delete objects from a relational database.

JPA provides a standard for applications to interact with relational databases so that developers don’t need to worry about vendor-specific differences among databases or writing time-consuming boilerplate code to persist data.

What is JPA?

Enterprise applications require efficient access to relational databases. For example, an event calendar application needs to create, retrieve, update, and delete the events that users add to their calendars. The application itself can’t efficiently store this data and must be able to quickly retrieve it from a database, complete the requested function, and if necessary, return it to persistent storage. In the past, configuring these tasks required developers to manage complex SQL operations and differences among vendor databases. JPA provides an extra level of abstraction between the application and the database, enabling developers to manage data persistence in a standardized way.

JPA is a Jakarta EE specification to represent data in relational database tables as Plain Old Java Objects (POJO), a process that is known as object-relational mapping (ORM). JPA simplifies and standardizes ORM by using Java annotations or XML to map Java objects into one or more tables of a relational database. The JPA specification explicitly defines ORM, rather than relying on vendor-specific mapping implementations. JPA is based on the Java programming model that applies to Jakarta EE environments, but it can function within a Java SE environment for testing purposes.

JPA simplifies the persistence programming model by providing the following functions:

  • The EntityManager API can persist, update, retrieve, or remove objects from a database.

  • The EntityManager API and object-relational mapping metadata handle most of the database operations without requiring you to write JDBC or SQL code to maintain persistence.

  • JPA provides the JPQL query language, which extends the independent EJB querying language. You can use JPQL to retrieve objects without writing SQL queries specific to the database that you are working with.

JPA is designed to operate both inside and outside of a Jakarta EE container. When you run JPA inside a container, the applications can use the container to manage the persistence context. If no container exists to manage JPA, the application must handle the persistence context management itself. Applications that are designed for container-managed persistence do not require as much code implementation to handle persistence, but these applications cannot be used outside of a container. Applications that manage their own persistence can function in a container environment or a Java SE environment.

JPA configuration with Open Liberty

JPA for Open Liberty is supported by the Jakarta Persistence feature and the Jakarta Persistence Container feature. The JPA feature includes JPA specification interfaces and container-managed JPA integration. EclipseLink is included as the default JPA provider implementation. If you want to use a different provider implementation, such as Hibernate, enable the JPA Container feature. The JPA Container feature provides the same capabilities as the JPA feature but does not include a default provider implementation. If you enable the JPA feature, you do not need to explicitly enable the JPA Container feature. The JPA feature automatically enables the JPA Container feature.

For examples of how to configure a provider implementation other than the default, see the Jakarta Persistence Container feature.

JPA and local transaction contexts (LTC)

Open Liberty provides both global and local transaction contexts to managed components. Providing these contexts to managed components and having threads to service managed components, a transaction is always active whether for a global transaction context (GTC) or a local transaction context (LTC).

This processing has no effect on application-managed persistence contexts, that is, JPA entity managers that are acquired through EntityManagerFactory instances that are injected into an application with the @PersistenceUnit annotation. However, it can affect container-managed persistence contexts (CMTS), that is, JPA entity managers that are injected through the @PersistenceContext annotation.

JPA API methods require that a TransactionRequiredException exception is thrown when they are called outside of the boundaries of a GTC, and this exception is still thrown as expected. However, while the LTC remains active and until a new GTC is started or the end of the component service invocation is reached, the CMTS persistence context remains active. Entities that are fetched by using either find or query by a CMTS entity manager within the bounds of an LTC are still managed by that persistence context, instead of becoming immediately detached. As a result, the persistence context that is kept alive by the LTC is disposed of once the GTC starts, and entities that are managed by that persistence context become detached. This outcome might seem like an unexpected behavior and a difference in behavior with some JPA programming guides.