Persistence: EntityManager (Enterprise JavaBeans 3.1)

 

Persistence is a key piece of the Java EE platform. In older versions of J2EE, the EJB 2.x specification was responsible for defining this layer. In Java EE 5, persistence was spun off into its own specification. Now, in EE6, we have a new revision called the Java Persistence API, Version 2.0, or more simply, JPA.

Persistence provides an ease-of-use abstraction on top of JDBC so that your code may be isolated from the database and vendor-specific peculiarities and optimizations. It can also be described as an object-to-relational mapping engine (ORM), which means that the Java Persistence API can automatically map your Java objects to and from a relational database. In addition to object mappings, this service also provides a query language that is very SQL-like but is tailored to work with Java objects rather than a relational schema.

In short, JPA handles the plumbing between Java and SQL. EJB provides convenient integration with JPA via the entity bean.

Entity beans, unlike session and message-driven types, are not server-side components. Instead, they are simple objects whose state can be synchronized with an underlying persistent storage provider. They are created just like any normal instance, typically using the new operator, and have no special APIs that must be implemented by the Entity class.

Much like EJB’s server-side types, however, entity beans gain powerful services when used within the context of the container. In the case of persistence, Entity instances may become managed objects under the control of a service called the javax.persistence.EntityManager.

In the Java Persistence specification, the EntityManager is the central authority for all persistence actions. Because entities are plain Java objects, they do not become persistent until your code explicitly interacts with the EntityManager to make them persistent. The EntityManager manages the object-relational (O/R) mapping between a fixed set of entity classes and an underlying data source. It provides APIs for creating queries, finding objects, synchronizing, and inserting objects into the database. It also can provide caching and manage the interaction between an entity and transactional services in a Java EE environment such as the Java Transaction API (JTA). The EntityManager is well integrated with Java EE and EJB but is not limited to this environment; it also can be used in plain Java programs.

You can use Java Persistence outside of an application server and in plain Java SE programs.

This topic focuses on the details of the persistence service and how it can be accessed within Java EE.


Entities Are POJOs

Entities, in the Java Persistence specification, are plain old Java objects (POJOs). You allocate them with the new() operator just as you would any other plain Java object. Their state is not synchronized with persistent storage unless associated with an EntityManager. For instance, let’s look at a simple example of an Employee entity:

tmp95169_thumb1_thumb1tmp95170_thumb2_thumb2tmp95171_thumb_thumb

If we allocate instances of this Employee class, no magic happens when new() is invoked. Calling the new operator does not magically interact with some underlying service to create the Employee in the database:

tmp95172_thumb_thumb

Allocated instances of the Customer class remain POJOs until you ask the EntityManager to create the entity in the database.

Managed Versus Unmanaged Entities

Before we can go any deeper into the entity manager service, we need to delve more deeply into the lifecycle of entity object instances. An entity bean instance is either managed (aka attached) by an entity manager or unmanaged (aka detached). When an entity is attached to an EntityManager, the manager tracks state changes to the entity and synchronizes those changes to the database whenever the entity manager decides to flush its state. When an entity is detached, it is unmanaged. Any state changes to an entity that is detached are not tracked by the entity manager.

Persistence Context

A persistence context is a set of managed entity object instances. Persistence contexts are managed by an entity manager. The entity manager tracks all entity objects within a persistence context for changes and updates made, and flushes these changes to the database using the flush mode rules discussed later in this topic. Once a persistence context is closed, all managed entity object instances become detached and are no longer managed. Once an object is detached from a persistence context, it can no longer be managed by an entity manager, and any state changes to this object instance will not be synchronized with the database.

When a persistence context is closed, all managed entity objects become detached and are unmanaged.

There are two types of persistence contexts: transaction-scoped and extended persistence contexts.

Transaction-scoped persistence context

It’s important to be aware of a transaction in simple terms to discuss Entities. For the purposes of this discussion, we may think of a transaction as a set of beginning and end boundaries. Everything executed in between must either fully succeed or fully fail, and state changes made within a transaction are visible elsewhere in the system only when the end boundary completes successfully.

Persistence contexts may live as long as a transaction and be closed when a transaction completes. This is called a transaction-scoped persistence context. When the transaction completes, the transaction-scoped persistence context will be destroyed and all managed entity object instances will become detached. Only persistence contexts managed by an application server may be transaction-scoped. In other words, only EntityManager instances injected with the @PersistenceContext annotation or its XML equivalent may be transaction-scoped.

tmp95174_thumb_thumb

When getTheWorldsBestGuitarist() is executed, the EJB container invokes it within the context of a JTA transaction. An Employee reference is pulled from the EntityManager, and the setName() method is used to change the name of the employee. The Employee instance that the EntityManager returns will remain managed for the duration of the JTA transaction. This means that the change made by calling the set Name() method will be synchronized with the database when the JTA transaction completes and commits.

The Employee instance is also returned by getTheWorldsBestGuitarist(). After the JTA transaction completes, the transaction-scoped persistence context is destroyed, and this Employee instance is no longer managed. This means that if setName() is called after it becomes detached, no changes will be made to any database.

Extended persistence context

Persistence contexts may also be configured to live longer than a transaction. This is called an extended persistence context. Entity object instances that are attached to an extended context remain managed even after a transaction is complete. This feature is extremely useful in situations where you want to have a conversation with your database but not keep a long-running transaction, as transactions hold valuable resources such as JDBC connections and database locks. Here’s some small pseudocode to illustrate this concept:

tmp95175_thumb_thumb

In this example, a local variable, pageMcConnell, is initialized by calling the EntityManager.find() method in transaction 1. Unlike a transaction-scoped persistence context, the Employee instance pointed to by this local variable remains managed. This is because extended persistence context stays alive past the completion of transaction 1. In transaction 2, the employee is updated and the changes are flushed to the database.

Extended persistence contexts may be created and managed by application code, and we’ll see examples of this later in this topic. They can also be created and managed by stateful session beans.

Detached entities

Entity instances become unmanaged and detached when a transaction scope or extended persistence context ends. An interesting side effect is that detached entities can be serialized and sent across the network to a remote client. The client can make changes remotely to these serialized object instances and send them back to the server to be merged back and synchronized with the database.

This behavior is very different from the EJB 2.1 entity model, where entities are always managed by the container. In EJB 2.1, applications using entity beans always had a proxy to the entity bean; in EJB 3.x, we work with concrete instances of plain Java classes. For EJB 2.1 developers, this behavior will seem strange at first, since you are used to the container managing every aspect of the entity. You’ll find that after you get used to the new EJB 3.x model, your application code actually shrinks and is easier to manage.

The reason we can eliminate code is very simple to illustrate. EJB 2.1 code often used the Value Object Pattern (often called Data Transfer Objects). The idea of this pattern was that the entity bean exposed a method that copied its entire state into an object that could be serialized to remote clients (like a Swing application) that needed access to the entity’s state:

tmp95176_thumb1_thumb1

This is exactly the kind of plumbing we earlier deemed evil when discussing the benefits of using a Container and Application Server. Application code, armed with the right tools, should be free of this kind of error-prone and excessive noise.

Also, it is very expensive to make a remote method call to an entity bean from a client. If the client had to call getFirstName(), getLastName(), etc., to get information about a customer it was displaying, performance would suffer. This is where the Value Object Pattern came in. EJB 3.x eliminates the need for this pattern because persistent objects become value objects automatically when they are detached from a persistent context. One side effect we encounter in dealing with detached entities revolves around entity relationships, which we’ll discuss later.

Packaging a Persistence Unit

An EntityManager maps a fixed set of classes to a particular database. This set of classes is called a persistence unit. Before you can even think about creating or querying entities with an entity manager, you must learn how to package a persistence unit for use within a Java SE (regular Java application) or Java EE (application server) environment. A persistence unit is defined in a persistence.xml file, which is described by the JPA2 specification in section 8.2.1. This file is a required deployment descriptor for the Java Persistence specification. A persistence.xml file can define one or more persistence units. The JAR file or directory that contains a META-INF/persistence.xml file is called the “root” of the persistence unit, and this may be:

• An EJB JAR file

• The WEB-INF/classes directory of a WAR file

• A JAR file in the WEB-INF/lib directory of a WAR file

• A JAR file in an EAR library directory

• An application client JAR file

The structure of one of these JAR files may look like the following:

tmp95177_thumb_thumb1

The persistence.xml deployment descriptor defines the identities and configuration properties of each persistence unit described within it. Each persistence unit must have an identity, although the empty string is a valid name.

The set of classes that belong to the persistence unit can be specified, or you can opt for the persistence provider to scan the JAR file automatically for the set of classes to deploy as entities. When scanning is used, the persistence provider will look at every class file within the JAR to determine whether it is annotated with the @javax.persistence.Entity annotation, and if it is, it will add it to the set of entities that must be mapped.

Each persistence unit is tied to one and only one data source. In Java SE environments, vendor-specific configuration must be used to define and configure these data sources. In Java EE environments, specific XML elements define this association.

The root of the persistence.xml XML schema is the <persistence> element, which contains one or more <persistence-unit> elements. Each <persistence-unit> has two attributes: name (required) and transaction-type (optional). The subelements of <persistence-unit> are <description> (optional), <provider> (optional), <jta-data-source> (optional), <non-jta-data-source> (optional), <mapping-file> (optional), <jar-file> (optional), <class> (optional), <properties> (optional), and <exclude-unlisted-classes> (optional).

Here’s an example of a persistence.xml file:

tmp95178_thumb_thumb1

The name attribute defines the name by which the unit will be referenced. This name is used by injection annotations and XML deployment descriptor elements to reference this unit. This attribute is required.

The transaction-type attribute defines whether you want your persistence unit to be managed by and integrated with Java EE transactions (JTA) or you want to use the resource local (RESOURCE_LOCAL) javax.persistence.EntityTransaction API to manage the integrity of your EntityManager instances. This attribute defaults to JTA in Java EE environments and to RESOURCE_LOCAL in SE environments.

The <description> element is really just a comment describing the given persistence unit and is not required.

The <provider> element is the fully qualified name of a class that implements the javax.persistence.PersistenceProvider interface. In Java EE and SE environments, the persistence implementation is pluggable: your vendor provides an appropriate implementation. Usually, you do not have to define this element and can rely on the default value.

If you are using JTA or RESOURCE_LOCAL persistence units, you will probably define a <jta-data-source> or <non-jta-data-source> element, respectively. These elements specify a vendor-specific identity of a particular data source. Usually, this string is the global JNDI name for referencing the data source. If neither is defined, then a vendor-provided default will be used.

The <properties> element defines the set of vendor-specific attributes passed to the persistence provider. They specify configuration that is specific to a vendor implementation. Since there is no registry or JNDI service within Java SE, this is usually how vendors configure data sources, instead of using the <jta-data-source> and <non-jta-data-source> elements.

The Persistence Unit Class Set

A persistence unit maps a fixed set of classes to a relational database. By default, if you specify no other metadata within your persistence.xml file, the JAR file that contains persistence.xml will be scanned from its root for any classes annotated with the @javax.persistence.Entity annotation. These classes are added to the set of classes the persistence unit will manage. You can specify additional JARs that you want to be scanned using the <jar-file> element. The value of this element is a path relative to the JAR file that contains persistence.xml:

tmp95179_thumb_thumb

Scanning JAR files is guaranteed to work in Java EE environments but is not portable in Java SE applications. In theory, it may not be possible to determine the set of JAR files that must be scanned. In practice, however, this is not the case. Whether you do or do not rely on a JAR scan, classes can be listed explicitly with the <class> element:

tmp95180_thumb_thumb1

The Employee and AnotherEntity classes listed within the <class> elements are added to the persistence unit set along with any other classes scanned in the persistence unit’s archive. If you do not want the persistence.xmls JAR file to be scanned, then you can use the <exclude-unlisted-classes> element.

tmp95181_thumb_thumb

The final set of classes is determined by a union of all of the following metadata:

• Classes annotated with @Entity in the persistence.xml file’s JAR file (unless <exclude-unlisted-classes> is specified)

• Classes annotated with @Entity that are contained within any JARs listed with any <jar-file> elements

• Classes mapped in the META-INF/orm.xml file if it exists

• Classes mapped in any XML files referenced with the <mapping-file> element

• Classes listed with any <class> elements

Usually, you will find that you do not need to use the <class>, <jar-file>, or <mapping-file> element. One case where you might need one of these elements is when the same class is being used and mapped within two or more persistence units.

Obtaining an EntityManager

Now that you have packaged and deployed your persistence units, you need to obtain access to an EntityManager so that you can persist, update, remove, and query your entity beans within your databases. In Java SE, entity managers are created using a javax.persistence.EntityManagerFactory. Although you can use the factory interface in Java EE, the platform provides some additional features that make it easier and less verbose to manage entity manager instances.

EntityManagerFactory

EntityManagers may be created or obtained from an EntityManagerFactory. In a Java SE application, you must use an EntityManagerFactory to create instances of an EntityManager. Using the factory isn’t a requirement in Java EE, and we recommend that you don’t use it directly from application code.

tmp95182_thumb_thumb

The createEntityManager() methods return EntityManager instances that manage a distinct extended persistence context. You can pass in a java.util.Map parameter to override or extend any provider-specific properties you did not declare in your persis-tence.xml file. When you are finished using the EntityManagerFactory, you should close() it (unless it is injected; we’ll discuss this later). The isOpen() method allows you to check whether the EntityManagerFactory reference is still valid.

Getting an EntityManagerFactory in Java EE

In Java EE, it is easy to get an EntityManagerFactory. It can be injected directly into a field or setter method of your EJBs using the @javax.persistence.PersistenceUnit annotation:

tmp95183_thumb_thumb

The unitName() is the identity of the PersistenceUnit. When the PersistenceUnit is used, it not only injects the EntityManagerFactory, it also registers a reference to it within the JNDI ENC of the EJB.The EJB container is responsible for noticing the @PersistenceUnit annotation and injecting the correct factory:

tmp95184_thumb_thumb

When an instance of the stateless session bean is created, the EJB container sets the factory field to the persistence unit identified by “nameOfMyPu”. It also calls the setFactory2() method with the “nameOfAnotherPu” persistence unit.

In EJB, an injected EntityManagerFactory is automatically closed by the EJB container when the instance is discarded. In fact, if you call close() on an injected EntityManagerFactory, an IllegalStateException is thrown.

Obtaining a Persistence Context

A persistence context can be created by calling the EntityManagerFactory.create EntityManager() method. The returned EntityManager instance represents an extended persistence context. If the EntityManagerFactory is JTA-enabled, then you have to explicitly enlist the EntityManager instance within a transaction by calling the EntityMan ager.joinTransaction() method. If you do not enlist the EntityManager within the JTA transaction, the changes you make to your entities are not synchronized with the database.

EntityManager.joinTransaction() is required to be invoked only when an EntityManager is created explicitly using an EntityManagerFactory. If you are using EJB container-managed persistence contexts, you do not need to perform this extra step.

Using the EntityManagerFactory API is a bit verbose and can be awkward when you are making nested EJB calls, for instance. Fortunately, EJB and the Java Persistence specification are nicely integrated. An EntityManager can be injected directly into an EJB using the @javax.persistence.PersistenceContext annotation.

tmp95186_thumb1_thumb1

The unitName() attribute identifies the persistence. By default, a transaction-scoped persistence context is injected when using this annotation. You can override this default with the type() attribute. When you access this transaction-scoped EntityManager, a persistence context becomes associated with the transaction until it finishes. This means that if you interact with any entity managers within the context of a transaction, even if they are different instances that are injected into different beans, the same persistence context will be used.

You must never call close() on an injected entity manager. Cleanup is handled by the application server. If you close an entity manager, an IllegalStateException is thrown.

An EXTENDED entity manager can only be injected into a stateful session bean; stateless session and message-driven beans are pooled, and there would be no way to close the persistence context and release any managed entity instances. In order to obtain an extended context, a stateful session bean uses the @javax.persistence.Persistence Context annotation with a type of EXTENDED:

tmp95187_thumb_thumb

When this MyBean backing instance is created, a persistence context is also created for the injected manager field. The persistence context has the same lifespan as the bean. When the stateful session bean is removed, the persistence context is closed. This means that any entity object instances remain attached and managed as long as the stateful session bean is active.

It is strongly suggested that you use the @PersistenceContext annotation or the XML equivalent when using Java Persistence with EJBs. These features were defined to make it easier for developers to interact with entity beans. Entity managers created using EntityManagerFactory are more error-prone because the application developer has to worry about more things. For instance, the developer could forget to close() an entity manager and subsequently leak resources. Take advantage of the ease-of-use facilities of your EJB container!


Interacting with an EntityManager

Now that you have learned how to deploy and obtain a reference to an entity manager, you are ready to learn the semantics of interacting with it. The EntityManager API has methods to insert and remove entities from a database as well as merge updates from detached entity instances. There is also a rich query API that you can access by creating query objects from certain EntityManager methods:

tmp95189_thumb_thumbtmp95190_thumb1_thumb1

 

Example: A Persistent Employee Registry

From our simple Employee entity defined earlier, we can use the EntityManager facilities to perform CRUD (Create, Read, Update, Delete) operations and build a simple persistent registry of employees.

A Transactional Abstraction

Before we can take advantage of the EntityManager to flush and synchronize our changes with the database, we must set up a transactional context within which our code can run. Because we’re not going to delve into the full features of transactions until later, let’s define a simple abstraction that marks the beginning and end of the transactional context.

tmp95191_thumb_thumb1

From here we can construct simple java.util.concurrent.Callable implementations that encapsulate our JPA operations, and these will all run within a transaction that starts and ends with the invocation to wrapInTx. Let’s assume we have an instance called txWrapper that implements TxWrappingLocalBusiness for us.

Persisting Entities

Persisting an entity is the act of inserting it within a database. We persist entities that have not yet been created in the database. To create an entity, we first allocate an instance of it, set its properties, and wire up any relationships it might have with other objects. In other words, we initialize an entity bean just as we would any other Java object. Once we’ve done this, we can then interact with the entity manager service by calling the EntityManager.persist() method:

tmp95192_thumb1_thumbtmp95193_thumb1_thumb2

When this method is called, the entity manager queues the Employee instances for insertion into the database, and the objects become managed. When the actual insertion happens depends on a few variables. If persist() is called within a transaction, the insert may happen immediately, or it may be queued until the end of the transaction, depending on the flush mode (described later in this topic). You can always force the insertion manually within a transaction by calling the EntityManager.flush() method. You may call persist() outside of a transaction only if the entity manager is an EXTENDED persistence context. When you call persist() outside of a transaction with an EXTENDED persistence context, the insert is queued until the persistence context is associated with a transaction. An injected extended persistence context is automatically associated with a JTA transaction by the EJB container. For other extended contexts created manually with the EntityManagerFactory API, you must call EntityManager.joinTransaction() to perform the transaction association.

If the entity has any relationships with other entities, these entities may also be created within the database if you have the appropriate cascade policies set up. Java Persistence can also be configured to automatically generate a primary key when the persist() method is invoked through the use of the @GeneratedValue annotation atop the primary key field or setter. So, in the previous example, if we had auto key generation enabled, we could view the generated key after the persist() method completed.

The persist() method throws an IllegalArgumentException if its parameter is not an entity type. TransactionRequiredException is thrown if this method is invoked on a transaction-scoped persistence context. However, if the entity manager is an extended persistence context, it is legal to call persist() outside of a transaction scope; the insert is queued until the persistence context interacts with a transaction.

Finding and Updating Entities

The entity manager provides two mechanisms for locating objects in your database. One way is with simple entity manager methods that locate an entity by its primary key. The other is by creating and executing queries.

find() and getReference()

The EntityManager has two different methods that allow you to find an entity by its primary key:

tmp95194_thumb_thumb

Both methods take the entity’s class as a parameter, as well as an instance of the entity’s primary key. They use Java generics so that you don’t have to do any casting. How do these methods differ? The find() method returns null if the entity is not found in the database. It also initializes the state based on the lazy-loading policies of each property.

Once you have located an entity bean by calling find(), calling getReference(), or creating and executing a query, the entity bean instance remains managed by the persistence context until the context is closed. During this period, you can change the state of the entity bean instance as you would any other object, and the updates will be synchronized automatically (depending on the flush mode) or when you call the flush() method directly.

merge()

The Java Persistence specification allows you to merge state changes made to a detached entity back into persistence storage using the entity manager’s merge() method.

If the entity manager isn’t already managing an Employee instance with the same ID, a full copy of the parameter is made and returned from the merge() method. This copy is managed by the entity manager, and any additional setter methods called on this copy will be synchronized with the database when the EntityManager decides to flush. The original parameter remains detached and unmanaged.

The merge() method will throw an IllegalArgumentException if its parameter is not an entity type. The TransactionRequiredException is thrown if this method is invoked on a transaction-scoped persistence context. However, if the entity manager is an extended persistence context, it is legal to invoke this method outside of a transaction scope, and the update will be queued until the persistence context interacts with a transaction.

Now we can create a new Employee instance with new properties and synchronize this state with persistent storage:  

tmp95195_thumb1_thumb2

In this example, we are creating an Employee instance with a primary key ID of ID_DAVE. After we’ve performed this merge with the EntityManager, the dave instance’s state is synced to the DB, and the object returned from the merge call is a managed object. Changing his name via a traditional call to the setter method for his name will change the state of this object, and the EntityManager will propagate these changes to the database when the transaction completes.

Alternatively, we could have used EntityManager.find() to look up dave from the DB, and then directly changed the name upon that reference.

getReference() differs from find() in that if the entity is not found in the database, this method throws a javax.persistence.EntityNotFoundException and there is no guarantee that the entity’s state will be initialized.

Both find() and getReference() throw an IllegalArgumentException if their parameters are not an entity type. You are allowed to invoke them outside the scope of a transaction. In this case, any object returned is detached if the EntityManager is transaction-scoped but remains managed if it is an extended persistence context.

To prove that dave’s new name has been persisted, let’s look him up again from a new transaction.

tmp95196_thumb1_thumb1tmp95197_thumb1_thumb1

To illustrate the difference between managed and unmanaged objects, here we manually detach dave from the EntityManager. We can still change his name just as we did before, but now these changes will not be synchronized with the database.

Queries

Persistent objects can also be located by using the JPA Query Language. Unlike EJB 2.1, there are no finder methods, and you must create a Query object by calling the EntityManager’s createQuery(), createNamedQuery(), or createNativeQuery() methods:

tmp95198_thumb1_thumb1

Creating and executing a JPA QL query is analogous to creating and executing a JDBC PreparedStatement:

Query query = entityManager.createQuery(“from Employee c where id=2″); Employee employee = (Employee)query.getSingleResult();

New to JPA2 is the addition of the Criteria API, a fluent expression to programmatically build queries. In many ways this can be more flexible than the string-based JPA QL.

All object instances returned by find(), getResource(), or a query remain managed as long as the persistence context in which you accessed them remains active. This means that further calls to find() (or whatever) will return the same entity object instance.

Removing Entities

An entity can be removed from the database by calling the EntityManager.remove() method. The remove() operation does not immediately delete the employee from the database. When the entity manager decides to flush, based on the flush rules described later in this topic, an SQL DELETE is executed:

tmp95199_thumb1_thumb1

After remove() is invoked, the rick instance will no longer be managed and will become detached. Also, if the entity has any relationships to other entity objects, those can be removed as well.The remove() operation can be undone only by recreating the entity instance using the persist() method.

The remove() method throws an IllegalArgumentException if its parameter is not an entity type. The TransactionRequiredException is thrown if this method is invoked on a transaction-scoped persistence context. However, if the EntityManager is an extended persistence context, it is legal to invoke this method outside of a transaction scope, and the remove will be queued until the persistence context interacts with a transaction.

refresh()

If you are concerned that a current managed entity is not up-to-date with the database, then you can use the EntityManager.refresh() method. The refresh() method refreshes the state of the entity from the database, overwriting any changes made to that entity. This effectively reverts any local changes.

If the entity bean has any related entities, those entities may also be refreshed, depending on the cascade policy set up in the metadata of the entity mapping.

The refresh() method throws an IllegalArgumentException if its parameter is not managed by the current entity manager instance. The TransactionRequiredException is thrown if this method is invoked on a transaction-scoped persistence context. However, if the entity manager is an extended persistence context, it is legal to invoke this method outside of a transaction scope. If the object is no longer in the database because another thread or process removed it, then this method will throw an EntityNotFoundException.

contains() and clear()

The contains() method takes an entity instance as a parameter. If this particular object instance is currently being managed by the persistence context, it returns true. It throws an IllegalArgumentException if the parameter is not an entity.

If you need to detach all managed entity instances from a persistence context, you can invoke the clear() method of the EntityManager. Be aware that when you call clear(), any changes you have made to managed entities are lost. It is wise to call flush() before clear() is invoked so you don’t lose your changes.

flush() and FlushModeType

When you call persist(), merge(), or remove(), these changes are not synchronized with the database until the entity manager decides to flush. You can force synchronization at any time by calling flush(). By default, flushing automatically happens before a correlated query is executed (inefficient implementations may even flush before any query) and at transaction commit time. The exception to this default rule is find(). A flush does not need to happen when find() or getReference() is called, because finding by a primary key is not something that would be affected by any updates.

You can control and change this default behavior by using the javax.persistence.Flush ModeType enumeration:

tmp95200_thumb_thumb

AUTO is the default behavior described in the preceding code snippet. COMMIT means that changes are flushed only when the transaction commits, not before any query. You can set the FlushModeType by calling the setFlushMode() method on the EntityManager.

Why would you ever want to change the FlushModeType? The default flush behavior makes a lot of sense. If you are doing a query on your database, you want to make sure that any updates you’ve made within your transaction are flushed so that your query will pick up these changes. If the entity manager didn’t flush, then these changes might not be reflected in the query. Obviously, you want to flush changes when a transaction commits.

FlushModeType.COMMIT makes sense for performance reasons. The best way to tune a database application is to remove unnecessary calls to the database. Some vendor implementations will do all required updates with a batch JDBC call. Using COMMIT allows the entity manager to execute all updates in one huge batch. Also, an UPDATE usually ends up in the row being write-locked. Using COMMIT limits the amount of time the transaction holds on to this database lock by holding it only for the duration of the JTA commit.

Locking

The EntityManager API supports both read and write locks. Because locking behavior is closely related to the concept of transactions, using the lock() method is discussed.

unwrap() and getDelegate()

The unwrap() method allows you to obtain a reference to the underlying persistence provider object that implements the EntityManager interface. Most vendors will have API extensions to the EntityManager interface that can be executed by obtaining and typecasting this delegate object to a provider’s proprietary interface. In theory, you should be able to write vendor-independent code, but in practice, most vendors provide a lot of extensions to Java Persistence that you may want to take advantage of in your applications. The getDelegate() method was provided in JPA1; for now, it’s recommended that users call unwrap().

Next post:

Previous post: