The Java Persistence API (JPA) is the persistence-tier solution for the Java EE platform. Although a lot has changed in EJB 3 for session beans and MDBs, the changes in the persistence tier have truly been phenomenal. In fact, other than some naming patterns and concepts, JPA has very little in common with the EJB 2 entity bean model. JPA does not follow the container model (which is just not very well suited to the problem of persistence); instead, it follows an API paradigm similar to JDBC, JavaMail, or JMS. As you’ll soon see, the JPA EntityManager interface defines the API for persistence while JPA entities specify how application data is mapped to a relational database. Although JPA takes a serious bite out of the complexity in saving enterprise data, ORM-based persistence is still a nontrivial topic. We’ll devote the entire third part of this topic to JPA, namely topics 7 through 10.
In almost every step of our ActionBa-zaar scenario, data is saved into the database using JPA. We won’t bore you by going over all of the persistence code for the scenario. Instead, we’ll introduce JPA using a representative example and leave you to explore the complete code on your own. You’ll see what EJB 3 persistence looks like by revisiting the PlaceBid stateless session bean. As a reminder to how the bidding process is implemented, figure 2.7 depicts the various components that interact with one another when a bidder creates a bid in ActionBazaar.
Recall that the PlaceBidServlet calls the PlaceBidBean’s addBid method to add a Bid entity into the database. The PlaceBidBean uses the JPA EntityManager’s persist method to save the bid. Let’s first take a look at the JPA, and then we’ll see the EntityManager in action.
Working with the Java Persistence API
You might have noticed in listing 2.1 that we kept the code to save a bid into the database conveniently out of sight. The PlaceBid EJB’s addBid method references the hidden save method to persist the Bid object to the database. Listing 2.8 will fill in this gap by showing you what the save method actually does. The save method uses the JPA EntityManager to save the Bid object. But first let’s take a quick look at the fourth and final kind of EJB—the JPA entity. Listing 2.7 shows how the Bid entity looks.
Figure 2.7 PlaceBidServlet invokes the addBid method of PlaceBid EJB and passes a Bid object. The PlaceBidEJB invokes the persist method of EntityManager to save the Bid entity into the database. When the transaction commits, you’ll see that a corresponding database record in the BIDS table will be stored.
Listing 2.7 Bid entity
You probably have a good idea of exactly how object-relational mapping in JPA works just by glancing at listing 2.7, even if you have no familiarity with ORM tools such as Hibernate. Think about the annotations that mirror relational concepts such as tables, columns, and primary keys.
The @Entity annotation signifies the fact that the Bid class is a JPA entity Q. Note that Bid is a POJO that does not require a business interface, unlike session and message-driven beans. The @Table annotation tells JPA that the Bid entity is mapped to the BIDS table Q. Similarly, the @Column annotations Q indicate which Bid properties map to which bids table fields. Note that entities need not use getter- and setter-based properties. Instead, the field mappings could have been placed directly onto member variables exposed through nonprivate access modifiers. (You’ll learn more about access via entity properties and fields in topic 7.) The @ld annotation is somewhat special. It marks the bidlD property as the primary key for the Bid entity D Just like a database record, a primary key uniquely identifies an entity instance. We have used the @GeneratedValue annotation with strategy set to GenerationType.AUTO Q to indicate that the persistence provider should automatically generate the primary key when the entity is saved into the database.
NOTE If you have used EJB 2 you may remember that it was almost rocket science to generate primary key values with container-managed persistence (CMP) entity beans. With EJB 3 JPA, the generation of primary keys is a snap; you have several options, such as table, sequence, identity key, and so on. We’ll discuss primary-key generation in topic 8.
The Bid entity could have been related to a number of other JPA entities by holding direct object references (such the Bidder and Item entities). EJB 3 JPA allows such object reference-based implicit relationships to be elegantly mapped to the database. We’ve decided to keep things simple for now and not dive into this topic quite so early; we’ll discuss entity relationship mapping in topic 8.
Using the EntityManager
You’ve probably noticed that the Bid entity doesn’t have a method to save itself into the database. The JPA EntityManager performs this bit of heavy lifting by reading ORM configuration and providing entity persistence services through an API-based interface.
NOTE The EntityManager knows how to store a POJO entity into the database as a relational record, read relational data from a database, and turn it into an entity; update entity data stored in the database; and delete data mapped to an entity instance from the database. As you’ll see in topics 9 and 10, the EntityManager has methods corresponding to each of these CRUD (Create, Read, Update, Delete) operations, in addition to support for the robust Java Persistence Query Language (JPQL).
As promised earlier, listing 2.8 shows how the PlaceBid EJB uses EntityManager API to persist the Bid entity.
Listing 2.8 Saving a bid record using the EJB 3 JPA
The true magic of the code in listing 2.8 lies in the EntityManager interface. One interesting way to think about the EntityManager interface is as an "interpreter" between the object-oriented and relational worlds. The manager reads the ORM mapping annotations like @Table and @Column on the Bid entity and figures out how to save the entity into the database. The EntityManager is injected into the Place-Bid bean through the @PersistenceContext annotation Q. Similar to the name parameter of the @Resource annotation in listing 2.5, the unitName parameter of the @PersistenceContext annotation points to the persistence unit specific to ActionBazaar. A persistence unit is a group of entities packaged together in an application module. You’ll learn more about persistence units in topics 9 and 11.
In the save method, the EntityManager persist method is called to save the Bid data into the database Q. After the persist method returns, a SQL statement much like the following is issued against the database to insert a record corresponding to the bid:
It might be instructive to look back at listing 2.7 now to see how the EntityMan-ager figures out the SQL to generate by looking at the object-relational mapping annotations on the Bid entity. Recall that the @Table annotation specifies that the bid record should be saved in the BIDS table while each of the @Column annotations in listing 2.7 tells JPA which Bid entity field maps to which column in the BIDS table. For example, the bidld property maps to the BIDS.BID_ID column, the bidAmount property maps to the BIDS.BID_AMOUNT column, and so on. As we
discussed earlier, the @ld and @GeneratedValue value annotations specify that the BID_ID column is the primary key of the BIDS table and that the JPA provider should automatically generate a value for the column before the insert statement is issued (the 52 value in the SQL sample). This process of translating an entity to columns in the database is exactly what object-relational mapping and JPA is all about.
This brings us to the end of this brief introduction to the EJB 3 Java Persistence API—and to the end of this whirlwind topic. At this point, it should be clear to you how simple, effective, and robust EJB 3 is, even from a bird’s-eye view.
As we stated in the introduction, the goal of this topic was not to feed you the "guru pill" for EJB 3, but rather to show you what to expect from this new version of the Java enterprise platform.
This topic introduced the ActionBazaar application, a central theme to this topic. Using a scenario from the ActionBazaar application, we showed you a cross section of EJB 3 functionality, including stateless session beans, stateful session beans, message-driven beans, and the EJB 3 Java Persistence API. You also learned some basic concepts such as deployment descriptors, metadata annotations, and dependency injection.
We used a stateless session bean (PlaceBidBean) to implement the business logic for placing a bid for an item in an auctioning system. To access the bean, we built a very simple servlet client that used dependency injection. We then saw a stateful session bean (PlaceOrderBean) that encapsulated the logic for ordering an item, and we built an application client that accesses the PlaceOrderBean. We saw an example of an MDB, OrderBillingMDB, that processes a billing request when a message arrives on a JMS queue. Finally, we built an entity for storing bids and used the EntityManager API to persist the entity to the database.
Most of the rest of this topic roughly follows the outline of this topic. Topic 3 revisits session beans; topic 4 discusses messaging, JMS and MDBs; topic 5 expands on dependency injection and discusses such topics as interceptors and timers; and topic 6 explores transactions and security management in EJB. Topics 7 through 10 are devoted to a detailed exploration of the Persistence API. Finally, topics 11 through 16 cover advanced topics in EJB.
In the next topic, we’ll shift to a lower gear and dive into the details of session beans.