Chapter 8. Understanding Java persistence

This chapter covers

  • Managing entities
  • Using transactions
  • Choosing between JPA and Hibernate

Java persistence is the mechanism by which object-based entities are translated between the Java runtime environment and a relational database. It’s undoubtedly the most popular feature of the Java EE platform, perhaps even the Java language. This popularity can be attributed to the fact that persisting data is central to nearly all enterprise applications. For that reason, persistence is a core part of Seam. In fact, you can’t get very deep into a Seam application without encountering it. As you’re probably aware, you’ve been using Java persistence in the sample application since chapter 2—though solely the Java Persistence API (JPA) variety.

This chapter provides a crash course in Java persistence and prepares you to use it in Seam. The two frameworks covered are JPA—the standard persistence mechanism in Java EE—and Hibernate—the popular open source persistence framework–turned–JPA implementation, both of which Seam support out of the box. Given the fact that these APIs, and Seam’s built-in components to support them, are so similar, this chapter establishes a persistence terminology that can be used to address them both in a general way. At the end of this chapter, I compare JPA and Hibernate and you’ll learn whether it’s worth adhering to the Java EE standard or better to venture onto the bleeding edge with Hibernate, or if it’s possible to have it both ways. Since you can’t get far persisting data in the absence of explicit transaction boundaries, this chapter also covers the role transactions play in the Java persistence mechanism.

One important point missing from the discussion in the previous chapter is the role that the persistence context plays in the conversation. In this chapter, you’re introduced to the persistence context, and I show you how to extend it across multiple HTTP requests. In the next chapter, you’ll discover how Seam offers to manage the extended persistence context, using the conversation as a vehicle, so you can align the lifetime of the persistence context to the boundaries of a use case.

Trying to cover all aspects of Java persistence in a single chapter would be impossible, so the focus here is on understanding the concepts you need to know when using it with Seam. Besides, a number of books are available that explain the fundamentals of transactions and persistence using either JPA or Hibernate in tremendous detail. I highly recommend Java Persistence with Hibernate (Manning 2007) to start, as well as EJB 3 in Action (Manning 2007), JPA 101 Java Persistence Explained (SourceBeat 2008), and Spring in Action, Second Edition (Manning 2007). That only scratches the surface of what’s available.[1] By the end of this chapter, you’ll be ready to decide which persistence API to use and learn what Seam brings to the table with its own transaction and persistence management.

1 How many Hibernate books do we need? (See http://in.relation.to/Bloggers/MyStackOfHibernateBooks.)

8.1. Java persistence principles

Persisting data, and doing it consistently and reliably, is vital to enterprise business applications. But transactions and persistence are complex subjects. They are both technically challenging—to the point of being academic—and they can be difficult to manage and tune. The complexity is magnified by the fact that a lot of misinformation exists out there. Once you start down the wrong path, it can be expensive and time consuming to correct your approach. The goal of this section is to “reset” your view of Java persistence and examine its architecture.

8.1.1. Establishing expectations

Developers shouldn’t expect to sprinkle magic pixie dust on POJOs in hopes they will become persistent. You have to understand the underlying mechanisms and spend a respectable amount of time dedicated to getting the mappings to the database right. Java persistence is intended to make the process of persisting objects to the database easier, but the impression you get from reading many developer blogs is that Java persistence is expected to do all the work. This shallow, magic pixie dust approach is what got folks who spread fear, uncertainty, and doubt (FUD) about the capabilities of Hibernate and JPA into such hot water in the first place.

In contrast to what may have been reported in blogs, these frameworks are stunningly adept at handling and optimizing persistence operations. Sadly, developers are doomed from the start because of problems that stem from the stateless architecture of the frameworks that try to manage the persistence resources, not from poor or careless application code. For instance, the persistence context is often scoped to the thread-based (or database) transaction, or worse, each persistence operation. This usage scenario is the nexus of the most frequently reported “bug” in Hibernate: the unnerving LazyInitializationException. In this chapter and the next, you’ll learn why this exception happens and how not to fear it anymore. In the process, you’ll discover that the persistence context was intended to represent a unit of work (i.e., use case) and should therefore be held open until that work is complete.

Throughout this chapter, you can expect to learn about not only Java persistence but also the principles behind its design and how it is supposed to work. You’ll then appreciate the vital enhancements that Seam weaves into Java persistence, introduced in the next chapter. The definitions I present here are going to be integral to the remainder of the book, where I’ll assume you know how to use the persistence mechanism.

Fortunately for you, seam-gen sets up the persistence configuration so that you can focus on learning the core Seam concepts right out of the gate. The basic seam-gen configuration includes a data source connection pool, a persistence unit, a persistence manager, and a transaction manager. In chapter 2, you used seam-gen to build a set of entity classes and transactional components to manage the database by reverse-engineering the database schema. But you won’t always have seam-gen to do all the work for you, so you need to take the time to learn how to get started with Java persistence in a more hands-on manner and understand its moving parts.

8.1.2. The four pillars of Java persistence

From the perspective of the database, Java persistence is no different than any other database client. It performs read and write queries—nothing more, nothing less. However, from the developer’s perspective, Java persistence is so much more than that. In fact, the whole reason that Java persistence was created (and when I say Java persistence I am referring to object-relational mapping [ORM]) is to extract the SQL out of the code and replace it with object manipulation. The database operations take place transparently to reflect the changes in the state of the objects.

Don’t assume, though, that Java persistence was meant to shun SQL as an inferior technology. Rather, the goal is to take the burden of performing that SQL off you, the developer, a majority of the time and allow you to form an object representation of the database that fits more cleanly with the rest of the object-oriented application. The four pillars of Java persistence that form this abstraction over SQL are as follow:

  • Entities (entity classes)
  • The persistence unit (represented at runtime by a persistence manager factory)
  • The persistence manager
  • Transactions

 

Note

Java persistence encompasses both JPA and the native Hibernate API. Hibernate shares a close resemblance to JPA and therefore the persistence terminology introduced in this section applies to both frameworks. When I present code, only the JPA classes are shown.

 

Figure 8.1 illustrates the relationship between these constituents. The persistence unit organizes and manages metadata, which maps entities to the database. The persistence manager factory obtains the mapping metadata from the persistence unit and uses that information to create persistence managers. The persistence managers are responsible for moving entities between the Java runtime and the database, a process known as the entity life cycle. Operations performed by the persistence manager should always be wrapped within the scope of a transaction. A transaction can also encompass operations performed by two or more persistence managers as a single atomic unit.

Figure 8.1. The Java persistence ecosystem

The fundamental goal of Java persistence is to move data between entity instances and the database. You’ve already used entities quite extensively throughout this book. Let’s quickly shed some light on what has already been at play.

8.2. Entities and relationships

Entities in an ORM tool, such as JPA or Hibernate, are the join point between the application and the underlying database, transporting data between them, as illustrated in figure 8.2. Because they are such a central piece of the application, the entities should be treated as more than just dumb data holders. Seam allows you to bind entity classes directly to a JSF view to capture form data, establish prototypes for new transient instances, and lazy-load data in the view. These objects transcend the layers of a Seam application.

Figure 8.2. Managed entities are used to exchange data between the application and the database.

While the entities serve as a representation of the data stored in the database tables, they don’t have to mimic the database schema. That gap is filled by the mapping metadata.

8.2.1. Mapping metadata

The ORM tool gives you free reign to assemble your entity graph as you choose, perhaps by following domain-driven design or other common object-oriented principles. You then use the mapping metadata of the ORM tool to form-fit the classes to the database schema. The flexibility that the mapping provides includes, but is not limited to, preventing certain properties in the entities from being persisted to the database (using @Transient), using different names for the properties that are mapped to their respective columns (using @Column), organizing tables along an inheritance hierarchy (using @Inheritance), subdividing a table across multiple entities (using @SecondaryTable), or molding data from a single table into composite objects (using @Embedded). Naturally, there are limits to how far you can stretch the mappings. If the mapping requirements are too steep and the object model is rigid, you have to question whether the database schema is serving its purpose of representing the domain of the business or whether ORM is the right solution to your problem.

One of the benefits of having mapping metadata is that it can be used to export the schema at runtime and have it build the database tables, foreign keys, and constraints automatically. You’ve taken this approach for each entity that was added to Open 18 since running seam generate in chapter 2. You might recall the following two questions from the seam-gen questionnaire:

  • Are you working with tables that already exist in the database?
  • Do you want to drop and re-create the database tables and data in import.sql each time you deploy?

Had you answered no for the first question and yes for the second, you could’ve started your application from existing entities alone. You’d generate the user interface using the command seam generate-ui and Hibernate would build the database each time the application starts. You should appreciate that mapping metadata can either be the result of bottom-up development or consulted for top-down development (to follow up on a point made back in chapter 2).

Let’s next explore how entities help make the task of managing persistence data simpler, particularly related data.

8.2.2. Transitive persistence

One of the core benefits of entities in ORM is transparent association handling. There are two sides to this feature. The first side is the read operations. Managed entities can load associated entities on demand (a feature known as lazy loading) by traversing them within the confines of an active persistence context (and ideally within a transaction). The other side is the write operations. When an entity is flushed to persistence storage, modifications to any associated objects are also processed and synchronized with the database. When a managed entity is removed, the removal may cascade into child entities, depending on the attributes in the mapping. This process is referred to as transitive persistence.

Entities can save you a lot of time, not because they shield you from SQL but because they handle the majority of the grunt work necessary to store related objects in a database. However, to use ORM effectively, you must manage the persistence context and transactions appropriately—or confusion reigns.

8.2.3. Bringing annotations to the persistence layer

If you’ve bought into the benefits of annotations, you’ll likely use them to configure your entities. The standard Java persistence annotations (in the package javax.persistence.*) work in both JPA and Hibernate. In addition to the standard JPA annotation set, Hibernate has its own “vendor” annotations to support additional mapping features and association types that aren’t part of the JPA specification. Hibernate strives to be the prototype for future versions of the JPA specification, so some of these annotations represent early versions of what may become available in JPA. Seam also takes advantage of some of Hibernate’s other vendor extensions, such as manual flushing of the persistence context, covered in the next chapter.

The @Entity annotation is used to declare a Java class as an entity. You’ve seen this annotation used many times throughout this book, often accompanying the @Name annotation to allow the class to serve a dual purpose as persistence entity and Seam component. Listing 8.1 shows an excerpt of the Course entity, which is used to store information about a golf course. Several key mapping annotations are shown in this listing that define how the class maps to the table in the database.

Listing 8.1. A Java persistence entity class
   package org.open18.model;
   import ...;

   @Entity
   @Table(name = "COURSE")
   public class Course extends Serializable {
       private Long id;
       private Facility facility;
       private String name;
       private Set<Hole> holes = new HashSet<Hole>(0);
       ...

       @Id @GeneratedValue
       @Column(name = "ID", unique = true, nullable = false)
       public Long getId() { return this.id; }
       public void setId(Long id) { this.id = id; }

       @ManyToOne(fetch = FetchType.LAZY)
       @JoinColumn(name = "FACILITY_ID", nullable = false)
       public Facility getFacility() { return facility; }
       public void setFacility(Facility facility) {
           this.facility = facility; }

       @Column(name = "NAME", nullable = false, length = 50)
       public String getName() { return this.name; }
       public void setName(String name) { this.name = name; }

       @OneToMany(cascade = CascadeType.ALL,
           fetch = FetchType.LAZY, mappedBy = "course")
       public Set<Hole> getHoles() { return this.holes; }
       public void setHoles(Set<Hole> holes) { this.holes = holes; }
       ...
   }

It is also possible to define all of the entity metadata in XML mapping files, regardless of whether you’re using JPA or Hibernate. In JPA, all of the XML mappings are declared in the file META-INF/orm.xml. Hibernate reads XML mappings from individual *.hbm.xml files. Consult the reference document for Hibernate[2] or the Hibernate EntityManager (JPA)[3] for details on using the mapping descriptors in the respective frameworks.

2http://www.hibernate.org/hib_docs/reference/en/html_single/

3http://www.hibernate.org/hib_docs/entitymanager/reference/en/html_single/

The metadata alone is not enough to allow these classes to be persisted. They must be associated with a persistence unit.

8.3. The persistence unit

The persistence unit groups the entities to be managed and determines how they are to be associated with a database runtime. It also indicates which transaction type is to be used when the database operations occur. The persistence unit consists of three main parts:

  • Entity metadata— A set of all annotated classes or XML mappings to be managed, containing instructions for how Java classes and bean properties are mapped to relational database tables. It also indicates the relationships between entities and defines the global fetching strategy used to traverse relationships.
  • Persistence unit descriptor— Specifies which persistence provider to use (not applicable for native Hibernate), database connection information, transaction type and lookup, and vendor extensions.
  • Persistence manager factory— The runtime object representing the configuration of the persistent unit as a whole. The factory is used to create individual persistence managers that provide the services for managing entity instances.

It’s important to understand the distinction between application-managed and container-managed persistence managers. The former is where the application bootstraps the persistence unit and is responsible for creating its own persistence managers. The latter, which only applies to JPA, is where the container loads the persistence unit and dishes out persistence managers as requested. Regardless of which style of Java persistence you’re using, you must first set up a persistence unit.

8.3.1. Defining a JCA data source

There is one prerequisite for setting up a persistence unit: a data source. After all, the goal of persistence is to talk to a database, and the data source provides the channel to that resource. Application servers employ JCA to allow a database resource adapter to integrate with the server connection pooling. What that basically means is that it’s possible to stick a database connection configuration into JNDI and have it managed as a connection pool. Data sources can be of the nontransaction, local transaction, or XA transaction variety. Up until now, you’ve been using a local transaction, but you’ll get a chance to play with XA transactions in chapter 14 (online).

In JBoss AS, files that end in *-ds.xml are used to install a data source. seam-gen sets up one of these deployment artifacts for each profile, dev and prod, and puts it in the resources folder of the project. When the build runs, the file is shipped off to JBoss AS. If you’re using a different application server, such as GlassFish, you may set up the data source in the administration panel instead. As an alternative, you can define your database connection (JDBC) configuration directly in the persistence unit. In the case of JPA, this is done with vendor-specific JDBC properties (supported in Hibernate, TopLink Essentials, and OpenJPA).

Once the data source is in place, you’re ready to configure the persistence unit. The persistence unit descriptor hosts the only XML required in Java persistence.

8.3.2. The persistence unit descriptor

The persistence unit descriptor brings all the entity classes together under a single persistence unit and hitches them to an actual database. For JPA, the persistence unit descriptor is META-INF/persistence.xml, and for Hibernate it is hibernate.cfg.xml. Each has a distinct XML schema. Listing 8.2 shows the JPA persistence unit descriptor used in the Open 18 directory application.

Listing 8.2. A JPA persistence unit descriptor
  <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">
    <persistence-unit name="open18" transaction-type="JTA">   
      <provider>org.hibernate.ejb.HibernatePersistence</provider>    
      <jta-data-source>open18Datasource</jta-data-source>   
      <properties>
        <property name="hibernate.hbm2ddl.auto" value="validate"/>
        <property name="hibernate.dialect"
          value="org.hibernate.dialect.H2Dialect"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.transaction.manager_lookup_class"
          value=
          "org.hibernate.transaction.JBossTransactionManagerLookup"/>    

        </properties>
      </persistence-unit>
  </persistence>

The file in listing 8.2 identifies several key pieces of information that tell the container how to operate. The fact that there is only one <persistence-unit> node indicates that we’re connecting to a single database. There’s a one-to-one mapping between the persistence unit and the database. Therefore, if you’re working with several different databases, or one or more read-only replicas of a master database, you’ll need multiple persistence units, and hence multiple <persistence-unit> nodes.

The persistence unit configuration creates a persistence unit with the name open18, identifies Hibernate as the JPA provider, indicates which JNDI data source the persistence manager should use to obtain connections to the database, configures the persistence manager to use JTA transactions, and specifies which class maintains the JNDI names of the UserTransaction and TransactionManager objects. The TransactionManager lookup is only relevant for application-managed persistence. You can also use resource-local transactions—often referred to as entity transactions—in environments where JTA isn’t available or if you’d rather not use it. The remaining properties in the descriptor are specific to the Hibernate provider.

 

Note

The data source defined in the <jta-data-source> node (or optionally the <non-jta-data-source> node) of the persistence unit descriptor refers to a javax.sql.DataSource in JNDI. seam-gen creates applications that use this configuration. Alternatively, you can configure a JDBC connection using vendor-specific persistence unit properties. The JNDI data source is typically a better choice to offload management of this resource. Note that Seam uses the Embedded JBoss container to provide a local JNDI registry in which to store the data source in a testing environment.

 

So why use annotations for the mappings and XML for the persistence unit configuration? After all, they both represent metadata about how entity classes tie in to database columns and tables. The answer involves the essence of ORM.

One of the core principles of Hibernate and JPA is to abstract vendor-specific database information from the Java code. The entity mappings are generally fixed, regardless of which database you use, so annotations are appropriate. It’s still possible to override the entity mappings in XML if you really need to, perhaps because a different table-naming convention is used in a given database. This setup gives you the rapid development of using annotations without losing the flexibility of configuration provided by an XML descriptor. Where XML is best suited, though, is in defining the SQL dialect, transaction manager, connection URL, and credentials, which are practically guaranteed to change when you switch among databases or deployment environments. These property values can even be tokenized so that a build can sweep through and apply the appropriate replacement values.

There are important differences in how JPA handles the persistence unit descriptor in comparison to Hibernate. In JPA, the following rules apply:

  • The persistence unit descriptor must be located at META-INF/persistence.xml.
  • Annotated classes are automatically discovered unless indicated otherwise in the descriptor by declaring the <exclude-unlisted-classes> element.[4]

    4 In TopLink Essentials, you must set this property to false to enable automatic detection of entity classes.

  • In a Java EE environment, if META-INF/persistence.xml is present, the persistence units in this descriptor will automatically be loaded.[5]

    5 In Java AS 4.2, this only happens if META-INF/persistence.xml is packaged in an EJB JAR within an EAR.

As you can see, some optimizations in JPA allow it to follow configuration-by-exception semantics. The fact that you can’t change the location and name of the persistence unit descriptor may leave you scratching your head as to how to define multiple persistence units. Unlike the Hibernate configuration, JPA supports multiple persistence units within the same descriptor, so you don’t need separate files.

Hibernate does less work for you when setting up a persistence unit, perhaps as a trade-off for giving you more control. If you’re using JPA annotations, you must explicitly define each class in the Hibernate configuration file. You also need multiple Hibernate configuration descriptors (hibernate-database1.cfg.xml, hibernate-database2.cfg.xml) if you need multiple persistence units. Finally, Hibernate isn’t automatically loaded into the Java EE environment. If you want to stay away from the proprietary API and configurations of native Hibernate, you’re better off using Hibernate as a JPA provider. Putting JPA in front of Hibernate permits you to switch to a different JPA vendor more easily if you feel the need to do so.

Reading the persistence unit descriptor, interpreting the XML mappings, and scanning the classpath for entity annotations are expensive operations. They should be done only once, when the application boots. That’s the role of the persistence manager factory.

8.3.3. The persistence manager factory

When the persistence unit is loaded, either by the container or by the application, its configuration is stored in a runtime object known as the persistence manager factory. In JPA, the persistence manager factory class is EntityManagerFactory. The equivalent class in Hibernate is SessionFactory. Once the configuration is loaded into this object, it is immutable. For each persistence unit (either a single <persistence-unit> in a JPA persistence unit descriptor or the <session-factory> in a Hibernate configuration file), there’s a persistence manager factory object to manage it.

When the persistence unit is managed by the container, within a Java EE environment, the persistence manager factory can be injected into a bean property of a Java EE component (a JSF managed bean or an EJB component) using the @Persistence-Unit annotation:

  @PersistenceUnit
  private EntityManagerFactory emf;

In the absence of container-managed persistence, you must load the persistence unit in application code using the Persistence class. For instance, you could load the open18 persistence unit using a call to a static method on the Persistence class in JPA:

  EntityManagerFactory entityManagerFactory =
      Persistence.createEntityManagerFactory("open18");

The term persistence manager factory reflects its primary function: to create persistence managers. It’s a thread-safe object designed to be loaded once when the application starts and closed when the application ends for the sole reason that it’s very expensive to create. Therefore, it’s almost always stored in the application scope, the longest-running scope in the Servlet API.

That wraps up our discussion of the persistence unit. As you’ve learned, the persistence unit defines which entity classes are to be managed by the persistence API and specifies the resources involved, such as the database dialect and the transaction lookup mechanism. You’re now aware that the persistence unit can be loaded by the container or by the application. With the persistence runtime established, we can move on to the persistence manager, the real workhorse of Java persistence.

8.4. The persistence manager

The persistence manager is the API that you use to move entity instances to and from the database. It’s also used to track changes to the state of the entity instances that it manages to ensure those changes are propagated to the database. In JPA, the persistence manager class is EntityManager; in Hibernate, it is the Session class.

8.4.1. Obtaining a persistence manager

A persistence manager is created from a persistence manager factory. In contrast to the persistence manager factory, persistence managers are very inexpensive to create. In fact, they don’t even allocate an underlying JDBC connection until a transaction begins. Assuming you’ve managed to obtain a reference to an EntityManagerFactory, you’d use it to create an EntityManager instance as follows:

  EntityManager entityManager =
    entityManagerFactory.createEntityManager();

When container-managed persistence is being used (available in a Java EE environment), a persistence manager can be injected into a bean property of a Java EE component using the @PersistenceContext annotation, saving you from having to create it yourself:

  @PersistenceContext
  private EntityManager em;

You also have the option of creating your own persistence manager in a container environment by injecting a persistence manager factory, as shown earlier. Outside the container (such as in a Java SE environment or JavaBean component), you have no other choice but to create the persistence manager manually from a persistence manager factory. But that doesn’t mean you can’t delegate this task to Seam. As you’ll learn in the next chapter, Seam provides its own version of container-managed persistence so that you can inject a Seam-managed persistence manager into any component using @In. Seam’s solution also allows you to work with Hibernate in the same way.

8.4.2. The management functions of a persistence manager

The persistence manager is more than just a database mapper and query engine. It takes care of its entities from the moment they’re loaded until they’re kicked out the door. To that end, the persistence manager has three main responsibilities:

  • Manage entity instances within the scope of a single use case— Entities are managed via the persistence manager API. This API has methods to create, remove, update, find by id, and query entity instances. It also manages the life cycle of an entity instance as it moves between four possible states: transient, persisted, detached, and removed.
  • Maintain a persistence context— The persistence context is an in-memory cache of all entity instances that have been loaded into memory by this manager. It is the key to optimizing performance and enabling write-behind database operations (queued SQL statements). It’s often referred to as the “first-level” cache. The terms persistence context and persistence manager are often used interchangeably.
  • Perform automatic dirty checking— The state of managed objects that reside in the persistence context are monitored throughout the lifetime of the persistence context. When the persistence manager is flushed, the pending changes in the entity instances are sent to the database as a batch of SQL statements. Once an object becomes detached, changes to it are no longer monitored.

The persistence manager works at a higher level than SQL. It understands that data going to and from the database has a structure (the entity) and that this structured data has a life cycle, shown in figure 8.3. Entity instances start off as unmanaged, the transient state. They then become managed, allowing them to be synchronized with the database. If they are removed, that synchronization becomes a deletion. When a removal occurs, or the persistence context is closed, the entity instance becomes detached, which means it has been abandoned by the persistence manager and changes to it are no longer monitored.

Figure 8.3. The entity life cycle in a Java persistence (ORM) framework

The most significant aspect of the persistence manager is its persistence context. In fact, you could argue that the persistence context is what makes using Java persistence worthwhile. The persistence manager will forgo trips to the database when it recognizes that the requested instance has already been loaded into the persistence context. What’s more important is that the persistence manager guarantees uniqueness of each instance in the persistence context according to its identifier and the object identity of those instances is preserved. As a result, the persistence manager can monitor the state of the entity instances and will propagate changes made to them to the database, even cascading into related entities, whenever the persistence context is flushed. As long as the persistence manager remains open, you can traverse lazy associations and the persistence manager will go back to the database to load the data without requiring you to assemble a query. These features are what make it a persistence manager, not just a database access layer. But to use these features, the persistence context must be scoped appropriately.

8.4.3. Persistence context scoping

The persistence manager (and accordingly the persistence context) is often misrepresented as being bound to either a database connection or transaction. This misguided information was brought about by the persistence manager being misused as a means to an end in stateless architectures, popularized by the Spring Framework. The result is that many developers now fear keeping the persistence manager open for an extended period of time or believe that it isn’t supposed to remain open beyond the scope of a transaction. The persistence manager was actually designed to serve a use case, for however long that use case may last. The persistence manager will reestablish database connections as needed, and by no means does it leave connections open just because it lives on.

The truth of the matter is that when the persistence manager is scoped incorrectly, Java persistence can become more of a hindrance than a help. When the lifetime of the persistence manager is cut short, perhaps because it’s tied to a transaction, it leads to detached entity instances, a topic discussed in depth in section 8.6. By putting the persistence context on such a short leash, you’re stripping out all of its value as a manager of entity instances. The persistence manager was designed so that it could outlive a transaction and later be re-associated with a new transaction, informing that transaction, and the database, of the changes to the entities while it was away (a process known as dirty checking). Without this ability, the persistence manager is reduced to a mediator for accessing the database.

What you want to do is treat the persistence manager as a stateful object. That means letting it live through the request and beyond, a need filled by the conversation context. You have to be careful that you don’t put it in a shared scope, though, because the persistence manager is not thread safe. In section 8.6, you’ll learn how to extend the persistence context’s scope by letting a stateful session bean manage it. In the next chapter, you’ll see that the conversation is best suited for managing the persistence context, which is exactly how a Seam-managed persistence context is handled.

That covers how entities are formed and how they’re used to move data between the Java runtime and the database. But, as you know, data consistency is paramount to persisting data. A brief discussion of the purpose of transactions and how they’re controlled wraps up this crash course in Java persistence.

8.5. Transactions

Transactions are about as important as the persistence operations themselves. Without transactions, you’re risking corrupted or inconsistent data. It is crucial that whenever you perform work against a database, you ensure that the boundaries of a transaction are well defined and that all work is conducted within the scope of such a well-defined transaction.

8.5.1. Sorting out the transaction APIs

A database transaction is a grouping of SQL statements that perform an atomic unit of work. This grouping is demarcated by special database statements (e.g., BEGIN, COMMIT, or ROLLBACK). An alternative to issuing these statements explicitly is to use one of various Java transaction APIs responsible for handling this task. You have three choices:

  • JDBC transactions
  • Resource-local transactions
  • JTA transactions

At the most basic level, the JDBC API provides a thin wrapper around these statements. However, when you’re working with ORM, you want to work at a higher level to allow the ORM to involve the persistence context in the transaction commit. Resource-local transactions, represented by the RESOURCE_LOCAL constant in the JPA persistence unit descriptor, are those controlled via the persistence manager API (Hibernate or JPA). This is a descriptive term that can be translated as “database focused.”

When working with more than one persistence manager, you need an API that can facilitate a transaction across several resources. Java Transaction API (JTA) provides a comprehensive transaction manager that can handle several resources in a single transaction. JTA transactions are therefore referred to as global or system transactions.

JTA is a standard Java EE API and is favored when working in a Java EE–compliant environment. JTA is also used behind the scenes by EJB components that use container-managed transactions. Resource-local transactions are typically used in Java SE environments or servlet containers. If available, JTA is the best choice because it simplifies the task of obtaining an active transaction and issuing rollbacks. It can also enlist multiple resources into the transaction, so if you’re partway through development you don’t have to change your existing code if you must add a new transactional resource. Seam makes working with the various transaction APIs simple by providing a wrapper that can delegate to the configured transaction API.

Let’s now look at the guarantees that a transaction provides.

8.5.2. Atomic units of work

From the standpoint of the application, a transaction is an atomic unit of work. An atomic unit of work is a set of operations, or tasks, that you want to perform on the database. Since you’re working with Java persistence, you perform these operations against the persistence manager rather than the database. When you reach the point when you want to commit the changes to the database, you’re guaranteed by the transaction that either they all happen or none of them happen.

Keeping data consistent

Rather than rehash the overused bank account scenario to explain transactions, we’re going to talk golf! Consider that you use a tee-time reservation system to secure your time slot at your favorite golf course. As a user, you browse through the available times for your course and find one that fits best with your schedule. You pick one and then submit the form. The action method is then tasked with performing an atomic unit of work. The following code shows several operations that are performed within a resource-local transaction using JPA. Proper exception handling is excluded for clarity, but certainly not optional:

  entityManager.getTransaction().begin();
  Course course = entityManager.find(Course.class, courseId);
  TeeTime teeTime = new TeeTime(course, selectedDate);
  course.reserveTeeTime(teeTime);
  Golfer golfer = entityManager.find(Golfer.class, currentGolfer.getId());
  golfer.addTeeTimeToSchedule(teeTime);
  entityManager.flush();
  entityManager.getTransaction().commit();

The operations involve marking the time as occupied in the COURSE_SCHEDULE table and then adding a row to the GOLFER_SCHEDULE table so that you don’t forget about your obligation. The transaction guarantees that information in these two tables remains consistent—meaning they tell the same story. It ensures that if the insert operation were to fail on the GOLFER_SCHEDULE table, the slot would open back up on the COURSE_SCHEDULE table, and vice versa. You certainly don’t want tee times blocked off without anyone intending to show up. You also don’t want to show up to the golf course to find a foursome of golfers chatting at the first tee at your scheduled time.

 

Info

It’s often necessary to handle data exchange between two or more persistence managers (and in turn, two or more databases). This scenario calls for a distributed transaction that involves XA-compliant data sources. The XA transaction has the same guarantees but works using a Java-based transaction manager rather than delegating the establishment of transaction boundaries to the database.

 

The previous example mirrors the classic credit-debit account scenario often cited. Let’s consider another source of inconsistency that transactions can protect against.

It’s all or nothing

Assume that you’re adding a new golf course to the directory. You spent a good half hour collecting all the data for the course and populating the form. You click Submit to save your work. Once again, the action method is tasked with performing a unit of work. It must save the main information to the course table, a row for each hole in the HOLE table, a row for each tee set in the TEE_SET table, and finally a row for each tee (the number of tee sets times the number of holes) in the TEE table. Assume that somewhere along the line, one of the inserts chokes and the database kicks back an error. If a transaction wasn’t active, partial course information could be left spread across the tables. If you tried to submit the form again, it would bail out because the top-level record already exists in the database, even though its related data is incomplete. If the application is smart enough to handle incomplete course data, you may be able to start the form over by editing the data that was inserted, but programming for that situation is complicated. You have a mess on your hands. The damage is magnified if thousands of users are encountering the problem at once.

These two scenarios should give you a compelling reason to use transactions when interacting with the persistence manager. However, even if you’re not performing write operations, transactions are still important. In fact, for databases that support transactions, it’s impossible to execute a SQL statement without a transaction. It’s just that it doesn’t last longer than this one statement, behaving the same as auto-commit mode.

Reads need protecting too

The database will open and close a transaction on every operation if explicit transaction boundaries are not set. This mechanism is referred to as an implicit transaction. When you forgo the use of transactions, you’re just letting the database handle it for you, one SQL statement at a time. These repeated processes of opening and closing transactions incur an unnecessary performance cost (even if optimized). Therefore, even when you’re just reading data, you should do so within explicit transaction boundaries.

Using a transaction for successive read-only operations guarantees you the isolation that transactions provide. If the database were to change in the middle of the rendering process, for instance, a transaction could guarantee that you won’t end up showing some of the old and some of the new data. If you use Seam’s transaction management, you get at least two transactions per request: one that covers the execution of the actions and one that covers the rendering of the response (which you’ll learn about in the next chapter).

8.5.3. ACID abridged

A proper database transaction adheres to the ACID criteria. This acronym stands for Atomicity, Consistency, Isolation, and Durability. Each criterion is essential to ensuring the integrity of the database and the operations executed against it. However, from the standpoint of the business logic, worrying about the details of each criterion is too low-level. You can instead group them into two key guarantees, which, as an application developer, you want your business logic to adhere to:

  • All logically grouped operations succeed or the database remains untouched.
  • Your data isn’t intermixed with the data from other concurrent operations.

Although some may criticize this as an oversimplification of transactions, if it helps to bring along those developers who merely view transactions as something that makes JPA and Hibernate work, I will have done my job. If you’re interested in learning about the specifics of the ACID principle, consult the resources listed at the beginning of the chapter. To go deeper into the topic of transactions and concurrency, check out chapter 5 of Martin Fowler’s Patterns of Enterprise Application Architecture (Addison-Wesley Professional, 2002).

You’re now familiar with the four pillars of Java persistence and how they work together to exchange data between the database and object-based entities while at the same time ensuring that the integrity of the data is upheld. Although the operations on the database form the foundation of Java persistence, the state maintained by the persistence manager is the value added by this abstraction. That’s because any time you can avoid hitting the database, the more scalable your application will become (based on the assumption that the database is the least scalable tier). In the next section, you’ll learn about a lesser-known feature of Java persistence: using the persistence manager as a stateful context that extends the lifetime of managed entity instances over a series of requests, thus making database-oriented web applications more scalable and less cumbersome to develop and use.

8.6. Managing persistence in the enterprise

The servlet environment, an abstraction over the HTTP protocol, is a less-than-ideal setting for performing transactional data processing. The lack of continuity between the stateless HTTP requests means that database connections and persistence managers are constantly being turned over. To further disrupt continuity, a web application is typically partitioned into layers, relying on a data layer to perform Java persistence operations, then shut down connections afterwards. When a persistence manager is closed, the entities it manages become detached and no longer support lazy loading (at least they shouldn’t) or automatic dirty checking, two valuable features of ORM.

You can instill continuity by reusing the same persistence manager throughout the duration of a use case. That’s the design goal of the extended persistence context. In this section, we put Hibernate aside and focus on using JPA in a standard Java EE environment to implement an extended persistence context and explore the benefits of doing so. In the next chapter, you’ll learn how Seam mirrors this pattern using either JPA or Hibernate operating independently of Java EE.

8.6.1. Introducing the extended persistence context

Java EE 5 introduced the concept of an extended persistence context by marrying JPA and stateful session beans, both residents of the EJB 3 specification. The persistence manager in JPA is capable of managing a set of entity instances, but it also must be managed. Although it’s possible to place the persistence manager directly into a stateful scope (e.g., session or conversation), thus making it available across an arbitrary number of requests, it gets lost there with no dedicated watchman to close it when the stateful scope ends and nothing to provide thread safety, security, or transactions. All of these concerns are what EJB components were designed to handle. Given that the persistence manager is a stateful resource, it makes sense to have it managed by a stateful EJB component.

A stateful session bean (SFSB) is allocated by the EJB container for a single client and remains active (and managing state) until it’s removed by the client, potentially spanning multiple thread-based (or database) transactions. In a web application, this type of session bean is typically stored in the HTTP session, allowing it to span multiple requests. In the next chapter, you’ll learn that the most suitable context for an SFSB is the conversation, making a stateful session bean conversational as it was intended.

An SFSB is a fitting solution for enclosing the persistence manager and shielding it from the disturbance of HTTP requests being opened and closed during a use case. The only problem is that the default behavior of EJBs is to tie the persistence manager to the scope of the transaction, which typically lasts for the duration of a call to a transactional method (the exact duration depends on the propagation behavior of the transactions). This guarantees that the persistence manager will only be available for a single request; a new one is allocated on the next go-around. The result is that the persistence manager fails to serve the needs of this stateful component or the use case. The lifetime of the persistence manager needs to be aligned with that of the SFSB rather than the transaction—precisely the definition of an extended persistence context.

When the entity manager is injected into a stateful session bean using the Java EE 5 @PersistenceContext annotation, you have the choice of using a transactional or extended persistence context, defined by the annotation’s type attribute. The transaction-scoped persistence context, which is the default type, binds the EntityManager to the scope of the JTA transaction. An extended persistence context, on the other hand, keeps the EntityManager open for the lifetime of the SFSB, delaying the call to the persistence manager’s close() method until the SFSB is destroyed. Here’s an example showing how to inject an extended persistence context into an SFSB:

  @PersistenceContext(type = PersistenceContextType.EXTENDED)
  private EntityManager em;

Transactions and requests may come and go, but as long as the SFSB exists, the injected EntityManager remains open and manages the entity instances it has loaded. Let’s see what benefits this brings and how it simplifies database-oriented web development.

8.6.2. The benefits of an extended persistence context

Why would you want to use an extended persistence context? Simple: to prevent detached entities. An entity becomes detached when the EntityManager that loaded it is closed. Don’t get me wrong; detached entities are useful in that they erase the need for data transfer objects (DTOs). But you generally want to prevent entities from entering this state if you intend to return them to the persistence manager to be updated, you want to use them to load related objects, or you need to repeatedly access the same database records.

When the persistence manager is closed prematurely, it is being abused and so is the database. I use the term abused because instead of the persistence manager helping to save you time, it ends up getting in your way. As you wrestle with it, the database gets queried excessively, even though one of the main goals of ORM is to reduce the number of database reads. If you’re committed to using ORM, and seeing a return on your investment, it pays to learn to use it correctly. Using an extended persistence context

  • Allows safe lazy loading of entity associations and uninitialized proxies
  • Eliminates merging to synchronize detached entity instances to the database
  • Ensures only one object reference exists for a given entity identifier
  • Works in conjunction with optimistic locking to support long-lived units of work

I will walk you through the use case of updating a golf course to shed light on these benefits, showing how an extended persistence context remedies problems caused by use of a transaction-scoped persistence context. Here are the steps involved in that use case:

  1. A list of golf courses stored in the database is presented to the user.
  2. The user clicks on a course to be modified.
  3. An editor form is presented, populated with the course’s information.
  4. The user makes modifications to the course and clicks the Save button.
  5. The modified course is synchronized with the database.

This use case appears simple enough, but because of challenges of working with Java persistence in a web application, presented earlier, programming for this scenario can be made unnecessarily complex without proper treatment of the persistence manager. The good news is that the persistence manager practically handles the work for you if extended throughout the use case. Once you learn to wield the persistence context properly, you will be ready to take on tougher challenges than the one presented here. Let’s begin by looking at what lazy loading is and how it’s affected by the scoping of the persistence context.

Crossing lazy associations in the view

Lazy loading of entity associations has unfortunately established a bad reputation. The first thing that comes to mind in most developers’ minds when you talk about lazy loading is Hibernate’s LazyInitializationException. The culprit is the detached entity instance.

The associations between entities are represented as an object graph that mimics the relationships of the corresponding database tables. When you fetch an entity, you typically only want to grab a fraction of the total graph or risk loading a significant portion of the database. For example, if you retrieve a Course object, it would be very expensive to eagerly load its facility and all of its holes, tee sets, and tees. (It gets worse if the same eager load were to occur when performing a query for multiple Course objects.)

The alternative to eager fetching is to mark the associations as lazy. When you traverse the association on the Java object, the uninitialized object or collection of objects is loaded transparently. Although you need to be aware of when this type of loading is occurring, it’s neither risky nor a bad practice. See the accompanying sidebar to learn how the classic n+1 select problem can be averted when using Java persistence.

 

Batch fetching

JPA can be optimized to perform additional eager fetching when lazy loading is triggered to avoid the classic n+1 select problem. Consider what happens when you iterate over the items in a lazy collection. Without optimization, each item is fetched from the database individually. If the number of items in the collection is n, then the database is consulted once to load the parent and n additional times to retrieve each of the children. The persistence frameworks can be configured to batch-fetch the children when the iterator on the collection is accessed to reduce the number of database hits. In Hibernate, this behavior is controlled globally using the hibernate.default_batch_fetch_size property. It can also be set at the entity or association level.

 

Let’s see what the hang-up is about lazy loading. When the user selects a course to edit, the editCourse() method on a Seam session bean component is invoked. This method retrieves the Course entity instance using a transaction-scoped persistence manager:

  @Stateful
  @Name("courseAction")
  public CourseActionBean implements CourseAction {
      @PersistenceContext private EntityManager em;

      @Out private Course course;

      @Begin public void editCourse(Long id) {
          course = em.find(Course.class, id);
      }
      ...
  }

When the editCourse() method is called, the following events occur:

  1. A long-running conversation begins.
  2. A transaction is started.
  3. A new persistence manager is created and bound to the transaction.
  4. The Course entity instance is retrieved from the persistence manager by its identifier.
  5. The transaction is committed (and terminated).
  6. The persistence manager is closed.

The last step presents a problem. If the persistence manager is closed after the action method is invoked, the Course instance is detached when the view is rendered. Reading the scorecard data from the Course instance requires crossing several associations, including the collection of holes, tee sets, and tees, all of which are configured to use a lazy fetching strategy. These associations are sitting ducks for a LazyInitializationException. One such traversal may happen when accessing the holes:

  <ui:repeat var="hole" value="#{course.holes}">
    <th>#{hole.number}</th>
  </ui:repeat>

A call to the method getHoles() triggers an exception because the EntityManager that loaded the Course instance is no longer available to further communicate with the database. The same problem arises on postback, even if a lazy association wasn’t hit in the view.

 

Note

In my tests, Hibernate complains about lazy loading on detached entities, whereas TopLink Essentials (another JPA provider) doesn’t exhibit this behavior because it proactively creates a new EntityManager as needed. While you can avoid this exception by switching to TopLink Essentials, it doesn’t mean you’ve escaped the problem. It’s not semantically correct to allow an entity to load data from different persistence managers. The persistence manager should guarantee uniqueness for an entity of the same type and identifier. When you violate this assumption, you’re asking for conflicts.

 

You can avoid problems with lazy loading (properly) in one of two ways:

  • Touch all the lazy associations needed in the view while the transaction is active.
  • Ensure that the persistence manager stays open for the duration of the request.

The first solution is similar to eager fetching, and thus has the same problems. You may be able to inflate the related objects on the Course entity instance in this case, but this is laborious for everyone involved. Eventually you’re going to encounter a case where this eager fetch strategy puts too many objects in memory, puts too much unnecessary load on your database, or is simply impossible. Either way, you’re going to quickly grow tired of constantly trying to tiptoe around these association boundaries—I know I have. Lazy associations were designed to be traversed, so why can’t we traverse them?

The best solution is to set the type of the EntityManager that’s injected to EXTENDED. That way, the persistence manager remains open for the lifetime of the SFSB and you can cross lazy associations in the view and on subsequent requests to your heart’s content. With the editor rendering successfully, let’s now explore capturing the changes on postback.

Just say no to merging

Throughout this book, you’ve seen how JSF is used to bind input fields to properties of an object. While JSF takes care of updating the property values when the form is submitted, those changes still need to get propagated to the database if the object is an entity instance. Continuing with the current example, let’s assume that an instance of the Course entity is bound to input fields in the course editor. We consider what happens when the form is submitted depending on whether the entity instance is detached or managed. Let’s start by assuming that it is detached (and no lazy-load exceptions occurred during view rendering).

As you know, the persistence manager tracks the state of entity instances bound to it. Outside of the persistence manager’s realm, though, changes are not recognized.

When the entity instance is introduced to a new persistence manager, the entity instance is treated like a stranger. Even though the entity instance has an identifier, and perhaps pending updates, the new persistence manager can’t vouch for it. To get the changes into the database, you must force those changes onto the EntityManager by passing the detached instance to the merge() method:

  @PersistenceContext private EntityManager em;

  @End public void save() {
      em.merge(course);
  }

Merging is a crude operation and should be avoided if possible. It first loads an entity instance with the same identifier as the detached instance into the current persistence context, resulting in a database read. Then, the property values from the detached instance are copied onto the properties of the managed instance. The main problem with this operation is that merging clobbers any changes that may have been made to the database record since the detached instance was retrieved (unless object versioning is used). There are other problems as well. If an entity instance with the same identifier as the detached instance has already been loaded into the current persistence context, a non-unique object exception is thrown because the uniqueness contract of entities in a persistence context is violated. You may also run into a lazy loading exception if you hit an uninitialized association on the detached instance during the merge. Avoid merging if at all possible.

By using an extending persistence context, entity instances don’t become detached. Therefore, the persistence manager continues to track changes that are made to the entity. When it comes time to synchronize the entity with the database, calling the flush() method will do the trick within the scope of any transaction.

   @PersistenceContext (type = PersistenceContextType.EXTENDED)
   private EntityManager em;

   @End public void save() {
       em.flush();
   }

As you can see, the save() method just instructs the EntityManager to push any dirty state to the database. The persistence manager pays its dues in the following two ways:

  • You aren’t required to write code to tell the EntityManager to save the changes.
  • If no changes are made to the entity instance, no database writes occur.

The coolest part is that no matter how deep down in the object graph changes were made, those changes are pushed to the database on a flush() wherever cascading is enabled. You just don’t even have to think about how to write a SQL update statement anymore. The first benefit might get you home from work sooner, but it’s the second benefit that takes a step toward relieving the database and making the application more scalable. Reads and writes should occur only when different data needs to be exchanged with the database, not data that the application should already be tracking. That brings us to our next topic: the persistence context acting as a first-level cache.

Hey entity, have I seen you here before?

When you retrieve an entity instance from the persistence manager by its identifier (the value of @Id property), the persistence manager first looks to see if that instance has already been loaded into the persistence context. If so, it returns that instance and the database is spared a read. The persistence context can be combined with the conversation to maintain that “natural cache” of data that was introduced in the previous chapter.

There’s another benefit to the persistence context’s in-memory cache in addition to saving the database some cycles. If you keep the persistence manager open, it can guarantee that for as long as you work with it, you’ll never end up with two different objects with the same identifier in the persistence context. Simply put, you don’t have to implement your own equals() method (and thus the hashCode() method) to get the result of two equivalent lookups to be equal in the eyes of Java.

Let’s assume that you’ve defined the following method on your SFSB:

  public Course findCourseById(Long id) {
      return em.find(Course.class, id);
  }

If the SFSB uses a transaction-scoped entity manager, the following assertion will fail, whereas if it uses an extended entity manager, it will pass:

  assert courseAction.findCourseById(9L) == courseAction.findCourseById(9L);

Thus, by using an extended persistence context, you don’t have to put effort into achieving object equality for the duration of the use case. Trust that this prevents a lot of headaches.

Optimistic locking

The world doesn’t stand still while the user is thinking about what changes to make to the course. It’s possible that another user could have gone into the application and chosen to modify the same course. While you could instrument a locking routine on the record, there’s a better way that doesn’t inconvenience everyone when someone with a record “checked out” goes on a coffee break. The solution is to check for conflicts when the entity instance is being saved, termed optimistic locking.

JPA provides the @Version annotation, which accompanies the @Column annotation on a field intended to maintain the version of an object. The version is simply an integer (though it can also be a timestamp) that increments each time the entity is updated:

  @Version
  @Column(name = "obj_version", nullable = false)
  public int getVersion() { return version; }

When an update occurs, the version in the database is checked against the version in the entity instance. If they differ, the write is aborted and an application exception is thrown, which can be caught to notify the user of the situation.

This type of locking is termed “optimistic” because it hopes for the best and only aborts the update if the database record was changed externally. Pessimistic locking, which is a formal database lock, prevents anyone else from accessing the record while it’s being updated. Holding long-term locks on database resources is a bad idea for performance reasons, especially when it relies on a user interaction to be released. You’re far better off using optimistic locking and designing a UI to deal with conflicts when they occur.

Throughout this section, you’ve witnessed how hairy things can get when you use a transaction-scoped persistence manager and how easy persistence operations become, in contrast, when you switch to an extended persistence manager. Although there are cases when entity instances aren’t needed outside of a transactional method, the resounding argument here is “down with the transaction-scoped persistence manager.”

Although the SFSB appears promising as the steward of the external persistence context, it has several limitations, most notably that it relies on a Java EE environment. In the next chapter, you’ll discover that the Seam-managed persistence context can emulate and improve upon the extended persistence context in Java EE. In addition, a Seam-managed persistence context can be easily shared with Java EE and JavaBean components alike, gets around complex persistence context propagation rules in EJB, and brings an extended persistence context solution to Hibernate. You’ll also learn how the extended persistence context is aligned with a conversation to make it available for an entire use case.

8.7. Choosing between JPA and Hibernate

There’s been a lot of talk in this chapter about JPA and Hibernate, but I haven’t formally addressed how they relate to each other or discussed the benefits of choosing one over the other. Seam supports both persistence APIs out of the box, though seam-gen sets up applications to use JPA, implicitly making it the default in Seam. Even so, for every feature in Seam that involves JPA, there’s also a Hibernate complement. Before you begin developing your application, you need to decide which API you’re going to use.

To choose between native Hibernate and JPA, you need to know a little about the history they share. There’s a common misconception that Hibernate and JPA are the same thing. They are not. They do have many similarities, though. This section sets the record straight about how Hibernate relates to JPA and gets you thinking about which API might offer the best choice for your application.

8.7.1. How Hibernate relates to JPA

Hibernate served as one of several references when the JPA specification was being developed and can now be used as a JPA provider as an alternative to its native API. But, given that JPA is a specification, it encompasses an agglomeration of other persistence providers, which include Oracle TopLink Essentials (and its derivative, EclipseLink), BEA Kodo, OpenJPA (the open source version of Kodo managed by Apache), and JPOX, to name a few.[6] While Seam can theoretically support any JPA provider, truth be told, there are advantages to choosing the Hibernate implementation (Hibernate EntityManager), which will be summarized in the next section.

6 A more complete list can be found at http://en.wikibooks.org/wiki/Java_Persistence/Persistence_Products

Many of the JPA interfaces mimic those of Hibernate, differing only in name. Although the two APIs mostly overlap, as figure 8.4 illustrates, there are several features that Hibernate boasts that weren’t included in the JPA specification or that have been added since. On the other hand, some concepts were introduced in JPA that aren’t available in Hibernate.

Figure 8.4. The overlap between JPA and Hibernate. Hibernate can be used natively or as a JPA provider.

Now that you understand the common history that Hibernate and JPA share, let’s consider what differentiates them.

8.7.2. What sets Hibernate and JPA apart

Hibernate has been around a lot longer than the JPA specification and has the advantage of being a self-directing open source project, not held back by the (sometimes very slow) Java Community Process (JCP). JPA, on the other hand, has the advantage of leveraging the standard Java EE environment. While that word standard carries a great significance, you’re always going to get more features using the Hibernate APIs. The most important feature, and the one that the Hibernate developers felt should have been in JPA from the start, is manual flushing of the persistence context. This feature allows you to defer updates to the database until an explicit flush is issued, such as when the use case ends. Manual flushing is essential to implementing an application transaction (called an atomic conversation when managed in the context of a Seam conversation). You’ll learn about application transactions and how they’re related to conversations in the next chapter.

 

Info

It’s likely that manual flushing will make it into a future version of the JPA specification. By using Seam, you don’t have to wait. Seam offers declarative control over the flush mode of the persistence context. You define the boundaries, and Seam instruments the Hibernate extension for you. You must be using Hibernate to take advantage this feature.

 

Aside from manual flushing, I’d like to mention a couple of other unique features in Hibernate. One exciting feature is Hibernate Search, a recent extension that supports full-text searching using the Lucene search engine. There’s also an extensive set of association mappings that Hibernate supports over JPA, such as indexed collections. And who can forget Gavin’s most revered feature: postquery filters. Hibernate can also save keystrokes by allowing you to use shorthand for JPQL in the style of Hibernate’s HQL (e.g., “from Course” instead of “select c from Course c”) and generally has a more intelligent query parser. If you’re a person who thrives on bleeding-edge features, you’ll probably be most comfortable with Hibernate. One of the unique features of Hibernate, to give it credit, is its ability to use JPA annotations. So you take a hybrid approach, which Seam builds on further.

8.7.3. Seam’s hybrid approach

Does choosing JPA mean that you have to sacrifice features? What if you want to use JPA but still take advantage of what Hibernate has to offer? I have good news for you. By choosing Hibernate as the JPA provider and using Seam-managed persistence, which you’ll learn about in the next chapter, Seam allows you to get the best of both worlds. Seam does some fancy footwork behind the scenes to give your JPA EntityManager access to several of Hibernate’s extensions. The best part is that, for the most part, you can stick to using the standard JPA interfaces in your code. Seam distills the best features of both frameworks so that, with little or no casting, you get the following benefits:

Seam’s philosophy is to let you keep the standards close at hand and feed you with the extra features that the standard isn’t ready to dish out. If maintaining strict JPA portability is important to you, you’ll likely want to avoid using extensions that aren’t common across the persistence providers. However, my advice is that you shouldn’t let your choice to use JPA hold back your application. Take advantage of the capabilities of the JPA provider.

 

What about designing to interfaces?

If you’re an advocate of interface-based design, you may be shouting that the best way to abstract the persistence framework choice is to hide it behind an interface that uses the object repository pattern (as suggested in Eric Evans’s Domain-Driven Design: Tackling Complexity in the Heart of Software [Addison-Wesley, 2003]). A data access layer would absolutely fit into the Seam component model. You’re simply moving the dependency injections down a layer. Understand, though, that you still have to consider which persistence framework is going to get you to a working implementation faster. An interface is but an interface. You still have to implement it.

 

The Seam reference documentation sends a clear message regarding which persistence framework to choose. It recommends that you use JPA with Hibernate as the provider. Making this pairing allows you to adhere to JPA until you decide that it’s necessary to leverage Hibernate-specific features. If you discover along the way that you need Hibernate to make your application successful, you can easily tap into it. It also recommends that you use Seam-managed persistence, which you’ll learn about in the next chapter. As for the basics of Java persistence, I trust that you have what you need to get started and to understand the resources I recommended. You can also correct your colleagues when they make the claim that JPA and Hibernate are the same.

8.8. Summary

This chapter gave you the crash course in Java persistence that you need to use Seam’s managed persistence and transactions, covered in the next chapter. The four main elements of Java persistence were explored: entities, the persistence unit, the persistence manager, and transactions. I then explained the distinction between a transactional and extended persistence context, and expounded the benefits of having an extended persistence context. Finally, you learned how JPA differs from Hibernate, and I presented reasons why you would choose one over the other. I recommended that you use Hibernate as a JPA provider rather than the native Hibernate API so that you’re able to take advantage of Java EE standards while still having access to the extensions offered by Hibernate.

In the next chapter, you’re going to learn how Seam supplements Java persistence and how it does a better job of managing the persistence context than what’s provided by the Java EE container alone. You’ll also discover how Seam offers the same declarative transaction behavior for regular JavaBeans that EJB 3 session beans enjoy. Read on to see how Seam makes creating transactional applications a truly pleasant experience.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.160.181