JPA 实体管理器应该关闭吗?

我有下面的方法。

public Profile readUser(String email){
EntityManager em = EMF.get().createEntityManager();
return em.find(Profile.class, email);
}

以上实体管理器的使用方法是否可行? 是否需要关闭实体管理器? 请提出建议。

95435 次浏览

I suppose the answer is: it depends.

Your entity manager is the key to gain access to the context where entities reside. If your application is a JSE application, you have to consider what is the life expectancy of your context.

Let's consider that you will create an entity manager per user's request. So, while you are attending a given request, you will keep your entity manager open, and when you finish with it, you close it.

In a JSE application, you may have considered that you would like to keep your entity manager open the entire life of the application (supposing you're not dealing with big amounts of data) then you close it when your application shuts down.

Bottom line, when you open it and when you close depends entirely on your strategy and your design. You close it when you no longer need the entities in its context.

In your example, that is not evident, but since you're creating the EM in the method, you should close it before returning, otherwise, you will no longer have access to it again (unless you're keeping it in some registry, which is not evident in the code).

If you don't close it your entities will be kept as attached, even after you're done using them. Your context will be kept alive even when you can no longer access your EM.

The JPA Specification contains more details. In section 7.7 Application-managed Persistence Contexts it says:

When an application-managed entity manager is used, the application interacts directly with the persistence provider's entity manager factory to manage the entity manager lifecycle and to obtain and destroy persistence contexts.

All such application-managed persistence contexts are extended in scope, and can span multiple transactions.

The EntityManagerFactory.createEntityManager method and the EntityManager close and isOpen methods are used to manage the lifecycle of an application-managed entity manager and its associated persistence context.

The extended persistence context exists from the point at which the entity manager has been created using EntityManagerFactory.createEntityManager until the entity manager is closed by means of EntityManager.close.

An extended persistence context obtained from the application-managed entity manager is a stand-alone persistence context it is not propagated with the transaction.

[...] The EntityManager.close method closes an entity manager to release its persistence context and other resources. After calling close, the application must not invoke any further methods on the EntityManager instance except for getTransaction and isOpen, or the IllegalStateException will be thrown. If the close method is invoked when a transaction is active, the persistence context remains managed until the transaction completes.

The EntityManager.isOpen method indicates whether the entity manager is open. The isOpen method returns true until the entity manager has been closed. To actually understand how this works it is vital to understand the relationship between the entity manager and the context.

So, as you can see 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="EmplService")
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 stateful session beans you might like the context to survive multiple bean invocations, since you don't like to commit until the bean has been marked for removal, right? In those cases, you need to use an 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 stateful bean for removal.

@PersistenceContext(unitName="EmplService", 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 stateful 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, is that 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 on 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, your context will be created and destroyed with your entity manager.

Or, you could create an 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.