In few project I have been successfully using
#PersistenceUnit(unitName = "MiddlewareJPA")
EntityManagerFactory emf;
...
EntityManager entityManager = emf.createEntityManager();
to obtain EntityManager for Database connection, but some days ago I was trying to move my project to Jboss EAP 6.2 and it couldn't create EntityManager. I was googling it and I found that I should try change #PersistenceUnit to
#PersistenceContext(unitName = "MiddlewareJPA")
private EntityManager entityManager;
to obtain EntityManager. It worked but I don't know why. What is the difference bettween PersistenceUnit and PersistenceContext? What are pros and cons of each one? Where should we be using one of them?
PersistenceUnit injects an EntityManagerFactory, and PersistenceContext injects an EntityManager. It's generally better to use PersistenceContext unless you really need to manage the EntityManager lifecycle manually.
I don't know how it works exactly in the Java EE, but in Spring, when you specify #PersistenceContext annotation, it injects EntityManager. Where does it get EntityManager? It is wrong to create one EntityManager for the whole application lifetime by calling EntityManagerFactory.createEntityManager(). So instead a special implementation of EntityManager interface is used and instantiated directly. It has an internal mutable thread-local reference to a real EntityManager. Implementations of methods just redirect calls to this real EntityManager. And there is a servlet listener, that before each request obtain EM by calling EMF.createEntityManager() and assign it to that inner reference of special EM. Also this listener manages transactions by calling getTransaction().begin(), .commit() and .rollback() on the real EM. It is very simplified description of performed work. And I believe, that JEE container does the same thing, as Spring does.
In general case it is better to inject EntityManager, because with EntityManagerFactory and #PersistenceUnit you should create/destroy EntityManager every time by hands and manage transactions too.
EntityManager obtained via #PersistenceContext is called Container Managed EntityManager as container will be responsible for managing "EntityManager". EntityManager obtained via #PersistenceUnit / entityManagerFactory.createEntityManager() is managed in the application by the developer. (for e.g. managing lifecycle of EntityManager, releasing the resources acquired by EntityManager, etc.).
Related
I'm working on a legacy codebase and saw something unsettling in our custom repositories. EntityManager is autowired into the repos directly. For example:
#Repository
public class OperationRepository {
// Yikes
private final EntityManager entityManager;
private QOperation operation = QOperation.operation;
#Autowired
public OperationRepositoryImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public Optional<Operation> findOneByIdAndType(Long operationId, OperationType type) {
JPAQuery<Operation> query = new JPAQuery<>(entityManager);
QOperation qOperation = QOperation.operation;
query.select(operation).from(operation)
.where(
operation.type.eq(type),
...
}
}
My understanding is that this is dangerous since EntityManager is not threadsafe and is being managed here as a field. I don't see an explicit definition in any of our configuration files to provide an EntityManager bean so am not sure what Spring does in this case.
I am going to start on the fix for using #PersistenceContext here instead but wanted to understand what the impact is on this being in production for so long and what consequences might have come from it.
Would we be limiting our connection pool size to the number of single entitymanagers in our repository beans? Are there any other dangers it could have caused? Or am I making too much of it?
It really depends on the configuration of your application context, which might get configured by Spring Boot if you are using that, but in general and with a typicals setup this is not a problem.
In such a setup the application context doesn't contain a single (or a limited set of) EntityManager instance but an EntityManagerFactory which can create EntityManager instances on demand.
And you don't get injected a normal EntityManager either, but a proxy which will point to different instances upon different calls, typically so that each thread has its own EntityManager and after a web request is completed the next request handled by the same thread gets a fresh instance.
If you are still concerned, I recommend to use a debugger to inspect the EntityManager and confirm that it is indeed a proxy and that it delegates to different actual instances for different threads.
You might also want to take a look at this question about Spring Scopes which is the underlying abstraction for this: Spring Bean Scopes
Is an EntityManager #Inject[ed] as follows in muliple classes threadsafe?
#PersistenceContext(unitName="blah")
private EntityManager em;
This question and this one seem to be Spring specific. I am using Jave EE CDI services
To my great surprise (after years of using jpa in spring) EntityManager is not thread safe. This is actually understandable if you think about it deeper: EntityManager is just a wrapper around native JPA implementation, e.g. session in Hibernate, which in turns is a wrapper around jdbc connection. That being said EntityManager can't be thread safe as it represents one database connection/transaction.
So why does it work in Spring? Because it wraps target EntityManager in a proxy, in principle using ThreadLocal to keep local reference per each thread. This is required as Spring applications are built on top of singletons while EJB uses object pool.
And how can you deal with that in your case? I don't know cdi but in EJB each stateless and stateful session bean is pooled, which means you cannot really call method of the same EJB from multiple threads in the same time. Thus EntityManager is never used concurrently. That being said, injecting EntityManager is safe, at least into stateless and stateful session beans.
However injecting EntityManagerto servlets and singleton beans is not safe as possibly several threads can access them at the same time, messing up with the same JDBC connection.
See also
Mind thread-safety when injecting EntityManager
The EntityManager is not thread-safe
Although EntityManager implementations itself are not thread safe the Java EE container injects a proxy which delegates all methods invocations to a transaction bound EntityManager. Therefore each transaction works with it's own EntityManager instance. This is true for at least transaction-scoped persistence context (which is default).
If container would inject a new instance of EntityManager in each bean the below wouldn't work:
#Stateless
public class Repository1 {
#EJB
private Repository2 rep2;
#PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
#TransactionAttribute
public void doSomething() {
// Do something with em
rep2.doSomethingAgainInTheSameTransaction();
}
}
#Stateless
public class Repository2 {
#PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
#TransactionAttribute
public void doSomethingAgainInTheSameTransaction() {
// Do something with em
}
}
doSomething->doSomethingAgainInTheSameTransaction call happens in a single transaction and therefore the beans must share the same EntityManager. Actually they share the same proxy EntityManager which delegates calls to the same persistence context.
So you are legal use EntityManager in singleton beans like below:
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Repository {
#PersistenceContext(unitName="blah", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
}
Another proof is that there is no any mention of thread safety in EntityManager javadoc. So while you stay inside Java EE container you shouldn't care about concurrency access to EntityManager.
I feel I need to go deeper into this because my first answer was not absolutely true.
I will refer to JSR-220 (EJB 3.0). In section 5.2 Obtaining an EntityManager you may find:
An entity manager may not be shared among multiple concurrently
executing threads. Entity managers may only be accessed in a
single-threaded manner.
Well that's it. You may stop reading here and never use EntityManager in singleton beans unless properly synchronized.
But I believe there is a confusion in the spec. There are actually two different EntityManager implementations. The first is one is provider implementation (saying Hibernate) which is not obliged to be threadsafe.
On the other hand there is a container implementation of EntityManager. Which is also not supposed to be threadsafe according to the above. But container's implementation acts as a proxy and delegates all calls to the real provider's EntityManager.
So further in the spec in 5.9 Runtime Contracts between the Container and Persistence
Provider:
For the management of a transaction-scoped persistence context, if
there is no EntityManager already associated with the JTA transaction:
The container creates a new entity manager by calling
EntityManagerFactory.createEntityManager when the first invocation of
an entity manager with Persistence- ContextType.TRANSACTION occurs
within the scope of a business method executing in the JTA
transaction.
This means in turn that there will be a different EntityManager instance for each transaction started. The code that creates an EntityManager is safe according to 5.3:
Methods of the EntityManagerFactory interface are threadsafe.
But what if there is an EntityManager associated with JTA transaction? The code that binds an EntityManager associated with current JTA transaction may be not threadsafe according to the spec.
But I can't really think of an application server implementation that works correctly with EntityManager injected into stateless beans and not correctly within singletons.
So my conclusions are:
If you want to follow the JSR-220 strictly then never use EntityManager in singletons until synchronizing the access to it.
I personally will continue to use EntityManager in singleton because my application server implementation works perfectly with it. You may want to check your implementation before doing so.
This is probably something trivial, but I'd love some help.
I get:
javax.ejb.EJBException: java.lang.IllegalStateException: Illegal to call this method from injected, managed EntityManager
11:54:37,105 ERROR [STDERR] at org.jboss.ejb3.tx.Ejb3TxPolicy.handleExceptionInOurTx(Ejb3TxPolicy.java:77)
11:54:37,105 ERROR [STDERR] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:83)
11:54:37,105 ERROR [STDERR] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)
when doing:
#PersistenceContext(unitName = "someName")
private EntityManager em;
...
final EntityManager entityManager = getEntityManager();
final EntityTransaction tx = entityManager.getTransaction(); // here
Can anyone tell me what the cause might be ?
It is illegal to obtain a reference to the EntityTransaction instance associated with the EntityManager in a Java EE managed context. From the Java EE API documentation of EntityManager.getTransaction():
Return the resource-level EntityTransaction object. The
EntityTransaction instance may be used
serially to begin and commit multiple
transactions.
Returns:
EntityTransaction instance
Throws:
IllegalStateException - if invoked on a JTA entity manager
The last line is pertinent in this context.
When you inject the EntityManager in an EJB deployed on an application server using the #PersistenceContext or #Inject annotations, the EntityManager will be managed by the container and not by the application. A container managed entity manager must be a JTA Entity Manager; application-managed entity managers can be resource-local entity managers. This is dictated by the JPA specification:
An entity manager whose underlying
transactions are controlled through
JTA is termed a JTA entity manager.
An entity manager whose underlying
transactions are controlled by the
application through the
EntityTransaction API is termed a
resource-local entity manager.
A container-managed entity manager
must be a JTA entity manager. JTA
entity managers are only specified for
use in Java EE containers.
Inferring from the first point (regarding the IllegalStateException), you must not obtain the EntityTransaction reference for container injected EntityManagers. You may however do so, if the container injected only the EntityManagerFactory, and your application obtained the EntityManager reference by invoking EntityManagerFactory.getEntityManager.
Additionally, it should be noted that invoking EntityManager.getTransaction() is meaningless for JTA entity managers. This is indicated by the JPA specification, in the definition of the EntityTransaction interface:
The EntityTransaction interface is used to control resource transactions on resource-local entity managers.
On the topic of managing the JTA transaction itself, if you need to manage the transaction boundaries yourself (i.e. use bean-managed transactions), inject the UserTransaction instance. Or if you wish to have the container manage the transaction, then simply annotate the method or the bean, with the appropriate TransactionalAttribute value.
It is usually not a good idea to use resource-local entity managers (and data sources) with bean managed or container managed transactions in an application server, but it can be done.
You will find a suitable example demonstrating the use of BMTs with injection of the EntityManager in the Hibernate EntityManager documentation. CMTs are even more trivial if you've already annotated your bean classes or methods; you merely have to avoid invoking the the getEntityTransaction() method for CMTs to work.
If you wish to understand further, I would recommend reading Chapter 7 of the JPA 2.0 specification, titled "Entity Managers and Persistence Contexts". The examples provided in the chapter demonstrate:
how JTA entity managers ought to be used in an application server (which is typically the place where they are used).
how resource-local entity managers may be used in an application server.
how resource-local entity managers can be used in a Java SE application.
You don't need to instantiate the EntityManager by hand, your container does that for you because of the
#PersistenceContext annotation. Also, you don't need to begin the transaction manually, it's also provided by your containter. Just use your em field and forget about the other ones.
I'm using IBM RAD to develop some JPA entities, and from those, corresponding JPA Manager Beans. Manager beans (which are generated by RAD) have the following member:
#PersistenceUnit
private EntityManagerFactory emf;
I'm not sure how to correclty instantiate (or get a reference to) this manager bean from a stateless EJB (3.0), so I've added a constructor to manager bean where I can pass EntityManagerFactory instance to it. I get a reference to EntityManagerFactory in an EJB by using `#PersistenceUnit' annotation like so:
#PersistenceUnit
private EntityManagerFactory _entityManagerFactory;
This seems rather unnecessary and I believe there must be a way to tell the container (Websphere 7.0 in my case) to 'bootstrap' this for me somehow, so that I get a reference to JPA manager bean right away. Is it?
Update:
It seems I haven't bean elaborate enough. Sorry for that.
There are three objects involved: JPA Entity, JPA Entity Manager and a Stateless EJB.
JPA Entity Manager class (not an EJB) is created by RAD and has convinience methods (named queries) on it. It also has defined member #PersistenceUnit private EntityManagerFactory emf. I know I can use EntityManager directly, but I'd like to use MyEntityManager for it's convinience methods.
I can get a reference to EntityManager or EntityManagerFactory in a stateless EJB by using annotations described above (and also like Bozho suggests)
I would like to get a reference to JPA Entity Manager in a stateless EJB. If I 'new' it up (new MyEntityManager()), the emf field is null. The workaround is to declare #PersistenceUnit field in an EJB and then pass it to JPA Entity Manager and use that.
Come to think of it, maybe I could declare JPA Entity Manager as an EJB and be done with it... (although this again seems unnecessary). I thought there is a method along the lines PersistenceContext.getJpaManager(MyEntityManager.class) which I am perhaps missing.
#PersistenceContext
private EntityManager em;
It seems you have your custom bean that you want to inject in other beans (it needs a local interface at least):
#EJB
private MyEntityManager em;
I am testing a Seam application using the needle test API. In my code I am using the getEntityManager() method from EntityHome. When I run the unit tests against an in memory database I get the following exception:
java.lang.IllegalStateException: No application context active
at org.jboss.seam.Component.forName(Component.java:1945)
at org.jboss.seam.Component.getInstance(Component.java:2005)
at org.jboss.seam.Component.getInstance(Component.java:1983)
at org.jboss.seam.Component.getInstance(Component.java:1977)
at org.jboss.seam.Component.getInstance(Component.java:1972)
at org.jboss.seam.framework.Controller.getComponentInstance(Controller.java:272)
at org.jboss.seam.framework.PersistenceController.getPersistenceContext(PersistenceController.java:20)
at org.jboss.seam.framework.EntityHome.getEntityManager(EntityHome.java:177)
etc ..
I can resolve some of these errors by injecting the EntityManager with
#In
EntityManager entityManager;
Unfortunately the persist method of EntityHome also calls the getEntityManager. This means a lot of mocks or rewriting the code somehow. Is there any workaround and why is this exception thrown anyway? I am using Seam 2.2.0 GA by the way.
There is nothing special about the components. They are generated by seam-gen. The test is performed with in memory database - I followed the examples in http://jbosscc-needle.sourceforge.net/jbosscc-needle/1.0/db-util.html.
In Seam what is the difference between injected EntityManager and getEntityManager from EntityHome ?
No one.
When using getEntityManager from EntityHome, Seam will lookup a Seam-managed persistence context named entityManager. If you set up your Seam-managed persistence context with other name than entityManager, your EntityHome will throw an Excedption.
Here is the default implementation of getEntityMananger in EntityHome
public EntityManager getEntityManager() {
return (EntityMananger) Component.getInstance("entityManager");
}
And when using a #In-jected EntityManager, Seam will do as shown above. Both are the same Seam managed persistence context.
Remember Seam performs lookup through #In-jected Component field name. For instance:
#In
EntityManager entityManager;
Because EntityManager field name is entityManager, Seam will perform a hierarchical search by using this name;
Here and here you can see how to set up a Seam Managed Persistence context.
regards,