Introduction
Java Persistence API (JPA) provides POJO (Plain Old Java Object) standard and object relational mapping (OR mapping) for data persistence among applications. Persistence, which deals with storing and retrieving of application data, can now be programmed with Java Persistence API starting from EJB 3.0 as a result of JSR 220. This API has borrowed many of the concepts and standards from leading persistence frameworks like Toplink (from Oracle) and Hibernate (from JBoss). One of the great benefits of JPA is that it is an independent API and can nicely integrate with J2EE as well as J2SE applications. [POJO – Plain Old Java Object is a term used to refer Java objects that do not extend or implement some specialized classes. Therefore, all normal Java objects are POJO’s only. The following classes are not POJO classes.
class MyServlet extends HttpServlet {} class MyRemote implements SessionBean {}
In the above cases, both MyServlet and MyRemote extends and implement specialized Servlet and Bean classes, therefore, these classes cannot be termed as POJO’s.
When we say that JPA follows the POJO standard, it follows that the entities (or the entity class) are very regular and normal Java classes, in the sense that they doesn’t need to extend or implement some specialized classes].
[OR Mapping – Object-Relation mapping is the process of the transformation of the data between the class objects and databases. Applications can depend on an OR-M like tool that greatly simplifies this work instead of manually coding the transformation process.]
About Persistence Entites
Persistent Data normally refers to permanent data in an application. The state of these data is made permanent by storing them in a persistent medium like database, files or a disk tape. In JPA terms, these persistent data are referred as entities. An entity refers to a logical collection of data that can be stored or retrieved as a whole. For example, in a banking application, Customer and BankAccount can be treated as entities. Customer name, customer address etc can be logically grouped together for representing a Customer entity. Similarly account number, total balance etc may be logically grouped under BankAccount entity.
Since entities form the heart of the JPA, they have some unique characteristics like persistability, identity and transactionability. The property of persistability deals with the storing and retrieving of entity from and to a persistent medium like database. Identity property is usually used to identity one unique entity among multiple entities (or multiple entity instances) in a database. All the CRUD operations (Create, Update and Delete) for entity objects will occur within a transactional context and it is one of the major characteristic for an entity object as the real state of an entity depends whether a transaction completes (commits/fails) or not.
Persistence API
All the classes, interfaces and annotations that make up the Java Persistence API are available in a single javax.persistence package. A brief look at the core objects and concepts within the package will be much useful before dealing with some sample code.
Entites
As mentioned previously, in JPA terms an entity refers to a persistent object which can be stored and retrieved from a persistent storage. In technical terms, this entity will correspond to a Java class.
Consider the following simple java class, named MobileEntity.
class MobileEntity{ private String model; private String manufacturer; private Double price; private String imeiNo; ….. // Getters and Setters go here. }
The above class represents a mobile object which has its own model, manufacturer, price and an imei number. Suppose, we wish to persist this mobile java class using JPA. The first step is to qualify this java class as an entity. This is done by marking the class with @Entity annotation. Marking a class with @Entity annotation will tell to the persistence engine that objects created from this class can use the support of JPA to make them persistent. After adding the @Entity annotation to the above class the code looks like this,
@Entity class MobileEntity{ private String model; private String manufacturer; private Double price; private String imeiNo; ….. // Getters and Setters go here. }[A persistence engine or a persistence provider is nothing but an implementation of the Java Persistence API. Java Persistence API is just a specification from Sun and not an implementation and vendors are free to implement their own persistent framework following the JPA specification. Thus, JPA provided a pluggable interface, where more and more implementations can easily be associated with it at run-time.]
Since an entity always has an identity associated with it, it is the job of the programmer to tell to the persistence engine, how uniquely to identity an entity object. This is simply done by marking a field (or a set of fields) with the @Id annotation. A field that is marked with @Id annotation will be treated as a primary key for the table by the persistent engine.
It is an error to ignore any one of the fields in an Entity class with @Id annotation, because the persistence engine won’t be in a position to identity unique entity objects without the help of primary keys. In our case, since no two mobile phones in the world share the same IMEI (International Mobile Equipment Identity), imeiNo is an ideal candidate to be marked with @Id annotation.
@Id private String imeiNo;
It is an error to give null values, to a primary key field, during that case, the persistence engine may throw any kind of database exception.
The following is the default values for table and column names when the persistence engine was Oracle’s Toplink during the deployment time.
- Alias Name – MobileEntity (the unqualified (with-out the package name) name of the class).
- Table Name – MOBILEENTITY
- Column Names – [MODEL, MAUNFACTURER, PRICE and IMEINO] (These correspond to the variable names).
Customizing the Entity object
In most of the cases, the defaults that are created and provided by a persistence engine are sufficient. However, certain situations may demand for customization which includes factors like name collision, companies adopting standard naming conventions, etc., like that. In such a case, the entity class can greatly be customized with a huge set of annotations available in the javax.persistence package. Let us take a look one by one.
Changing the default table name
By default the table name corresponds to the unqualified name of the class. We can change this behavior with the help of @Entity annotation itself, like this.
@Entity(name = "MOBILE_ENTITY") public class MobileEntity{ …… }
Now, the table name becomes MOBILE_ENTITY and this should be the name that must be referred in query strings (Queries are discussed later). The value to the name property must be legal in the sense, it cannot accept any keywords that are found in the query language.
Customizing the Column behaviors
The default name of the columns, their size, whether they can accept null values or not etc., can be customized using the @Column annotation. Following is the sample code that illustrates this,
@Column(name = "MOBILE_MODEL", nullable = true, length = 35) private String model; @Column(name = "MOBILE_MANUFACTURER" nullable = true, length = 100) private String manufacturer; @Id @Column(name = "MOBILE_IMEI_NO", nullable = false) private String imeiNo;
The name property, when specified will override the default column name (which is the same as that of the field name in the Entity class). The nullable property tells that whether the column can accept null values. Length property is only applicable if the type of the column is String (or VARCHAR). There are also properties like scale and precision which is applicable only when the type of the column is NUMBER.
[Note, multiple annotations can be legally applied to elements (like class, field, method etc.). In the above example the imeiNo has two annotations attached with it, namely @Id and @Column.]
Auto-generation of Primary Keys
A primary key for an entity which is usually annotated with @Id annotation can be given a value manually or we can depend on the persistence provider for the same. For this we have to use the @GeneratedValue annotation.
Consider the following example,
@Id @GeneratedValue(strategy = GenerationType.AUTO) private String imeiNo;
Since the imeiNo is going to be the primary key for the mobile object, we have decorated the field with @GeneratedValue annotation, which delegates the burden of creating values from developers to the persistence engine. Also, there are 4 different methods (or strategies) for primary key generation, which are AUTO, IDENTITY, SEQUENCE and TABLE. The simplest one is the automatic primary key generation strategy which is represented as GenerationType.AUTO.
[GenerationType is an Enumeration (new feature in Java 5.0) and the four different strategies for primary key generation, namely AUTO, IDENTITY, TABLE and SEQUENCE are defined in that enumeration.]
EntityManager
This class follows the standard Manager Design pattern for managing entities. Managing an entity or a set of entities refers to the act of bring a set of Java objects under the control of EntityManager. Unless entities don’t have any explicit association with EntityManager they are just ordinary java objects (though their corresponding classes have been marked with @Entity annotation).
This EntityManager API provides services for persisting an entity, removing an entity, querying and deleting entities.
In a J2SE application, a reference to an entity manager (EntityManager) can be obtained using the entity manager factory (EntityManagerFactory) and the Persistence class. The persistence class is a helper class (or a bootstrap) used to create EntityManagerFactory objects. With EntityManagerFactory objects, references to EntityManager objects can be obtained. The following code illustrates the same,
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PersistentUnitName"); EntityManager eManager = entityManagerFactory.createEntityManager();
[An EntityManagerFactory can be configured with some set of properties with the help of Persistent Units. Notice that one of the arguments to createEntityManagerFactory() is the name of the persistent unit which is discussed in the later sections.]
In a J2EE application, the container will directly inject a reference to the EntityManager using dependency injection, so the code becomes as simple like this,
@Resource private EntityManager entityManager;
Persistence Context
To be very precise, a persistent context manages a set of entities which in turn is managed by the EntityManager. A persistent context keeps track of the state (or the changes) that an entity object may undergo. And the EntityManager takes the support of this persistence context to commit or to undo the changes. As soon as an EntityManager object is created, it is implicitly associated with a persistence context for managing a set of entities.
Persistent Context comes in two flavors, one is the transaction-scoped persistent context and the other one is extended persistent context.
Transaction-Scoped Persistence Context: Imagine that a set of entities are managed by the persistence context. At this time, we say that the entities are bound to (or attached) to the persistent context. Changes may happen to these entities and these changes will occur within a transaction. Sometimes later when the transaction ends (commits or roll-back), the entities will unbind (detached) from the persistent context. As soon as the entities are detached from the persistence context, they are no longer being managed. Any changes that happen to these entities will not be persisted as they don’t have any association with the persistence context. Such kind of persistent context whose life-time is dependent on the life-time of the transaction (for a set of entities at that particular point of time) is termed as transaction-scoped persistent context.
All the transaction-scoped persistence context are configured by injecting @PersistentContext to EntityManager objects , like this,
@PersistenceContext(name="PersistentUnitName") private EntityManager entityManager;
[Note: There is no such public interface called PersitenceContext in the Java Persistence API. The EntityManager may implicitly depend on a virtual Persistence Context class for managing the entities. So, creating a transaction-scoped persistence context is nothing but creating an EntityManager object that has been configured with @PersistenceContext annotation.]
Extended Persistence Context: Unlike transaction-scoped persistence context, where the life-time of the persistence context will end as soon the transaction is completed, a persistence context may be configured to live even after a transaction completes. In such a case, all the entities that are managed by such a persistence context will still be in a manageable state only even after the transaction ends. They won’t be detached from the context. Such long-lived persistence context that will continue to exist even after the completion of a transaction is called extended persistence context.
All the extended persistence context objects are created and managed manually by the application code only (that is by the developers).
[As soon as an EntityManager object is created, an implicit Persistence context will be associated with it and it is soon kept open and prepared for managing a set of entities, meaning that the calling EntityManager.isOpen() method will always return true. Calling the EntityManager.clear() method will clear the current persistence context associated with the EntityManager and all the entities that have their associations will now be cleared and they become detached from the EntityManager. To release all the resources referenced by the EntityManager, call the close() method, After this method call, calling any of the methods will throw IllegalStateException.]Entities and Transactions
All entities have the property of transactionability and their CRUD operations will take place within a transactional context. Transactions can be broadly classified into two types based on who actually owns (or manages) the transaction. They are JTA and Resource-local transaction.
In the case of a J2EE Application, the default transaction type is JTA (Java Transaction API), unless explicitly specified. A method can be simply annotated with @RequiresNew (or @Requires) in which case a new transaction will always started by the container and the transaction completes as soon as the method ends.
Whereas in a J2SE application, the transaction-type defaults to Resource-local, which means that the developer (or the application code) has to explicitly start and end a transaction. It means that the user has to explicitly start a transaction with the help of EntityManager object, and then have to commit it, if everything goes normal, else have to roll-back the transaction if some error occurs.
The following code shows this,
EntityTransaction userTransaction = entityManager.getTransaction(); try{ userTransaction.begin(); // Do something here. // If everthing goes well, make a commit here. userTransaction.commit(); }catch(Exception exception){ // Exception has occurred, roll-back the transaction. userTransaction.rollback(); }
Operations on Entity Objects
The following are the legal operations that can be performed on Entity objects with the help of EntityManager API. As seen previously, EntityManager are objects that manage one or more entity objects with the help of an implicit persistence context.
Persisting Entity Objects:
Entity objects are like regular java objects until they become managed and made persistent by the EntityManager. The following piece of code makes an entity to become persistent and managed.
MobileEntity mobileObject = new MobileEntity(); mobileObject.set()... // Update the state values here. entityManager.persist(mobileObject);
The persist(entityObject) methods makes the entity persistent in the underlying database and managed within the persistence context of the EntityManager, whether the persistence context is a transaction-scoped or an extended persistence context depends upon how actually the EntityManager was configured.
[What happens when a managed entity is again forced to become managed by calling the persist() method. Or what happens when the persist() method is called couple of times on the same entity object.Whenever the persist() method is called, the persistence engine will check for the existence of that object with the help of its unique identifier (which is represented in the form of primary key). If any duplicate object is found, then a run-time exception, EntityExistsException will be thrown.]
Querying for Entities:
Developers can either depend on the EntityManager for simple search or Query objects for providing powerful search conditions for locating and querying entity objects.
Using EntityManager object:
Following are the two different methods available in EntityManager interface for querying entity objects and there are some major differences between the two.
Using the EntityManager.find() method:
The find() method takes the class name of the Entity object and the primary key value for locating a single entity object. If the object of interest cannot be located by the EntityManager, then this method will simply return null. The following code illustrates this,
MobileEntity mobile = entityManager.find(MobileEntity.class, "ABC-123"); If (mobile != null){ // mobile object may or may not be null. // Process the object. }
One good thing about the find() method is that, the returned entity object soon becomes managed automatically within the persistence context of the EntityManager.
Using the EntityManager.getReference() method:
This method, like the EntityManager.find() method, takes the name of the entity class and the primary key as their arguments. But the difference is, unlike the find() method which will return null if the entity object is not found, this method will throw an exception EntityNotFFoundException. Another difference between this method and the find() method is that, the entity that is fetched by this method may be lazily loaded. That is, the state of the state of entity (like model, manufacturer, imeiNo may be lazily loaded during the first time it is actually accessed).
MobileEntity mobile = entityManager.getReference( MobileEntity.class, "ABC-123"); // mobile object may not contain the actual state //values for model, manufacturer // and imei number, the states may be loaded during the first access. String model = mobile.getModel(); // The persistence engine may fetch the model value for the mobile here // at this particular point of time. …..
Using the Query object:
Discussed later.
Deleting Entities:
To remove (delete) an entity object from the database, make a call to EntityManager.remove(entityObject) method. The entity object that is passed to the remove() must be a managed entity, else the operation will fail.
Also, making this call may or may-not remove the entity immediately from the database. The algorithm that achieves the same is implementation specific. Some implementation may only mark the entity as a removed entity after this method call, and the actual deletion of the entity object in the database may happen when a flush() operation (which is discussed later) is made.
After this method call, the entity will become detached from the persistence context and it is no longer a managed one.
Updating Entities:
The EntityManager.merge(entityObject) method will make a detached entity to get associated with the current persistence context of the EntityManager. Consider the following lines of code.
// Transaction has begin. ….. MobileEntity mobile = entityManager.find(MobileEntity.class, "ABC-123"); ….. // Transaction ends. mobile.set()…… // Updating the mobile object. entityManager.merge(mobile);
In the above piece of code, a mobile entity object is located with the EntityManager.find() method. This entity is now in a managed state. Assume that the transaction ends after some point of time and also the persistence context is a transaction-scoped persistence context. As soon as the transaction completes, the persistence context will go off, (since the persistence context is a transaction-scoped persistence context). So the entity object becomes detached from the persistence context. After this any modifications that are made to the mobile object won’t be knowledgeable to the EntityManager as the mobile object has already been detached from it.
Now, calling the merge() method, will make the mobile object becomes managed, and all the recent changes that are made to it will become visible to the current persistence context of the EntityManager.
Flushing and Refreshing:
The EntityManager.flush() will synchronize all the changes that are made to the persistent entities back to the underlying database, whereas the EntityManager.refresh() does the reverse. It will update the entity object with values taken from the database. Any new values that are set to the entity objects will be lost as a result of this method call.
For example, consider the following piece of code,
MobileEntity mobile = ….. mobile.set(); // Update the state values for the mobile object. …. entityManager.flush(); // Calling this flush method will synchronize the database with the values // taken from the entity object.
Now consider this code,
MobileEntity mobile = … mobile.set(); // The state values for the mobile object is updated. ….. entityManager.refresh(); // The refresh() method will refresh the entity object //with the values taken from the database. // All the updates that are done are lost.
Summary
also read:
The above two links are continuous of this article with more features and the sample application for the JPA.This article began with the discussion of Java Persistent API and its advantages and what persistent entities are. Then the terminologies that are very specific to JPA like EntityManager, PersistenceContext have been discussed. The various features about the Query interface for locating Entity objects were explored in depth. Finally, it ended with Persistent Units and its relation with EntityManager objects along with a sample J2SE application.