Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does EntityManager's find() method create new instance of JPA class?

Tags:

java

jpa

ejb

I'm a bit confused. The question is in title, and here's why I'm asking. I have JSF + JPA web-application running on a single VM. And an JPA class has @Transient field. Now imagine some web user opens some page and executes code below

import javax.persistence.EntityManager;
// method 1 in backing bean
Agent a = entityManager.find(Agent.class, "007");
a.setTransientValue("Aston Martin");

What output should I expect when another web user/thread tries to read that transient value:

// method 2 in backing bean
Agent a = entityManager.find(Agent.class, "007");
String val = a.getTransientValue();

In other words, and in terms of JVM, does find() method return always new class instance or the same or 'it depends'? I've looked through JSR-220 for an answer, with no success, any help or doc reference would be appreciated.

like image 393
andbi Avatar asked May 11 '11 21:05

andbi


2 Answers

If you invoke find(..) within the same session (that is, within the same entitymanager lifetime), then the same object reference will be returned. The documentation of find() specifies this:

If the entity instance is contained in the persistence context, it is returned from there.

In other words, the EntityManager holds a collection (map most likely) of entities. When you call find it checks that collection. If the entity is not found there, a query to the database is made. The returned entity is put into the map, so subsequent calls will find it there.

But note again that this is only for the span of one session. This is usually the same as one http request (in the web app context)

like image 156
Bozho Avatar answered Sep 19 '22 00:09

Bozho


To actually understand how this works it is vital to understand the relationship between the entity manager and the context.

The entity manager is the public interface through which you access your entities, however, your entities reside in a context, attached to your entity manager. Understanding the life cycle of the different types of contexts will answer your question.

Persistence contexts can be of different types. In Java EE applications, you can either have a transaction-scoped persistence context or a extended-persistence context. In the JSE application, the nature of the context is controlled by the developer.

When you ask for an entity to your entity manager, it looks for the entity in its attached context, if it finds the entity there, then it returns it, otherwise, it retrieves the entity from the database. Subsequent calls for this entity in context will return the same entity.

Transaction-scoped

In a Java EE application using the transaction-scoped persistence context, when you first access your entity manager, it checks if the current JTA transaction has a context attached, if no context is yet present, a new context is created and the entity manager is linked to this context. Then the entity is read from the database (o from the cache if present) and it is placed into the context. When your transaction ends (commit or rollback), the context becomes invalid and whatever entities in it become detached. This is the classical scenario for stateless sessions beans.

@PersistenceContext(unitName="EmployeeService")
EntityManager em;

This also means that depending on how you design your transactions, you may end up with more than one context.

Extended-Persistence Context

In a Java EE application with statefull session beans you might like the context to survive multiple bean invocations, since you won't like to commit until the bean has been marked for removal, right? In those cases you need to use a extended persistence context. In this case, the persistence context is created when it is first needed, but it won't become invalid until your mark the statefull bean for removal.

@PersistenceContext(unitName="EmployeeService", type=PersistenceContextType.EXTENDED)

This means that, regardless of the instance of the entity manager that gets injected into this bean in subsequent calls of the statefull session beans methods, you can be sure you will always access the same context, and therefore, even subsequent calls will return the same instance, because it is the same context.

Also, your changes will not be flushed until the bean is marked for removal or you manually flush them.

Application-Managed

You can always instantiate manually your entity manager factory, and your entity manager. This is what you would typically do in a JSE application, right?

For this kind of applications you typically do not have a container to deal with the JTA transactions, right? So you use resource local transactions and you are responsible for manually committing or rolling back changes.

For this kind of application, when you instantiate your entity manager, a context is automatically attached to it.

Depending of your application, you can decide to create a global entity manager whose life cycle is attached to the life of the application itself. That is, a single entity manager for the entire life of the application. In this cases, you context will be created and destroyed with your entity manager.

Or, you could create a entity manager per conversation (i.e. transaction) with your application user. The scope in this case is determined by you, but still, your context will be created and destroyed with your entity manager.

like image 28
Edwin Dalorzo Avatar answered Sep 22 '22 00:09

Edwin Dalorzo