In a project of mine I'm trying to switch management of my persistence from application to container. I'm following these instructions: http://docs.oracle.com/javaee/6/tutorial/doc/gkhrg.html
I've read about EntityManager not being thread safe and just want to make sure that my setup is correct. My concern: http://weblogs.java.net/blog/2005/12/19/dont-use-persistencecontext-web-app.
I have a class that produces a persistence context.
#Singleton
public class JpaResourceProducer {
//The "pu" unit is defined with transaction-type="JTA"
#Produces
#PersistenceUnit(unitName = "pu")
#Database
EntityManagerFactory databasePersistenceUnit;
#Produces
#PersistenceContext(unitName = "pu")
#Database
EntityManager databaseEntityManager;
/* Alternative
#PersistenceContext(unitName = "pu")
private EntityManager em;
#Produces
#UserDatabase
public EntityManager create() {
return em;
}
public void close(#Disposes #Database EntityManager em) {
em.close();
}
*/
}
Then I have a jax-rs resource that injects a DAO.
#RequestScoped
#Path("/endpoint")
public class MyResource {
#Inject private Dao dao;
#GET
#Produces({MediaType.APPLICATION_JSON})
public Converter get() {
MyEntity entity = dao.find(1);
Converter converter = new Converter(entity);
return converter;
}
}
And finally a DAO where I inject the EntityManager.
#Singleton
public class JpaDao<T, K extends Serializable> implements Dao<T, K> {
protected Class<T> entityClass;
#Inject
#Database
EntityManager em;
public JpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
}
public T find(K id) {
return em.find(entityClass, id);
}
....
}
1. Is this a good setup in terms of thread safety and overall performance?
Bonus questions:
In the JpaResourceProducer I have an alternative setup for the EntityManager where I manually close the manager on dispose.
2. Is the container handling close of my EntityManager automatically?
The example from Oracle includes an EntityManagerFactory.
3. Do I really need an EntityManagerFactory when I'm using CMP?
What's your container? From annotations used I presume it is at least Java EE 6 Web Profile compatible, and in that case you're overcomplicating this.
The tutorial presents producting of multiple persistence units. Is this the case in your application? If not, plain injection into EJBs would be more relieable and less magical - I am also unsure about transactional behaviour of a singleton-produced persistence context.
Singleton JpaDAO means, there can be only one database operation at a time in your application, so this is serious performance bottleneck. It should be Stateless instead (and having its persistence context injected by traditional means).
In general, implement your DAOs and Business logic, even your JAX-RS endpoints as session EJBs, and let container handle concurrency and transactions properly.
Also use other sources of examples, e. g. Adam Bien's JavaEE Patterns.
Related
I'm trying to understand, how does injecting of EntityManger in Spring bean work.
I have bean
#Service
#RequiredArgsConstructor(onConstructor_ = #Autowired)
public class TestUpdateService {
#PersistenceContext
private EntityManager entityManager;
private final OrderRepository orderRepository;
#Transactional
public void doWork(Long id) {
Order order = orderRepository.findById(id).get();
entityManager.detach(order);
orderRepository.save(order);
}
}
And have a couple of questions:
Am I right that for every call of my transactional method doWork new instance of EntityManager will be created? I read (or mb misunderstood) on stackoverflow that entity manager annotated with #PersistanceContext creates own EntityManager for each transaction.
If it is so, does #Autowired work the same way?
If it isn't so, then how do these both annotations work?
I have a JPA/hibernate setup with multiple entity managers. What I am trying to do is dynamically injecting the entity manager in an abstract class used by multiple schemas with the same entity definition -- the tables are exactly the same across different databases in a single MySQL server. I am trying not to write unnecessary duplicate code, but I can't seem to find a way to inject the persistence context dynamically without duplicating a lot of code. Is there any way to do this?
Well, do you need to change the EntityManager that exists in a DAO instance? If yes, I'd say just switch your connection pool instead.
If instead you want to select to which instance to connect, set up the necessary keys in one or more profiles, then use that to get the necessary connection properties for your connection pool.
If you want to have multiple instance of the same DAO, use qualified beans and constructor injection to get the proper entity managers to them (abstract away everything else like factory / pool creation into methods).
I ended up creating an abstract DAO with all the basic list, update, delete methods and extending by another abstract DAO in which I set the entity manager for that particular set. Any DAOs that extend the last one will have the correct annotated entity manager associated with them. From that point on I am able to reuse my models, and all I have to do is extend the right DAO on my service layer.
The magic happens by calling setEntityManager(EntityManager em) using the #PerisstenceContext with the persistence unitName. I am not entirely sure why this works, but seems to do the trick.
Here's what I did:
AbstractJpaDao:
#MappedSuperclass
public class AbstractJpaDao <T>{
private Class<T> clazz;
protected EntityManager entityManager;
public final void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
#Transactional
public T getById(final long id) {
return entityManager.find(clazz, id);
}
//... all the others ...
}
InheritedDao1:
#MappedSuperclass
public class InheritedDao <T> extends AbstractJpaDao <T>{
//This is what allows me to inject the entityManager by its annotation
#PersistenceContext(unitName = "myPU")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
InheritedDao2:
#MappedSuperclass
public class OtherInheritedDao <T> extends AbstractJpaDao <T>{
//This is what allows me to inject the entityManager by its annotation
#PersistenceContext(unitName = "otherPU")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
Service1:
#Service
#Transactional(readOnly = true)
public class MyService extends InheritedDao<MyModel> {
public MyService() {
setClazz(MyModel.class);
}
}
Service2:
#Service
#Transactional(readOnly = true)
public class OtherService extends OtherInheritedDao<MyModel> {
public OtherService() {
//same model as used in MyService
setClazz(MyModel.class);
}
}
I would like to know which way is the best to define entity manager. I am using spring boot
case 1) creating in spring service class like follows
#Service
#Transactional
public class DemoService {
private static final Logger log = LoggerFactory.getLogger(DemoService.class);
private EntityManagerFactory emf;
public void getEntity(){
final EntityManager em = emf.createEntityManager();
}
#PersistenceUnit
public void setEntityManagerFactory(final EntityManagerFactory emf) {
this.emf = emf;
}
}
Case 2.) Define a global entity manager and share it across all services.
Note : Each service only reflects one single Entity definition.
Injecting the EntityManager is the simplest and the most effective way to do it:
#PersistenceContext(unitName = "persistenceUnit")
private EntityManager entityManager;
You don't need to set the EntityManagerFactory, since you need a transaction-bound EntityManager.
You don't need to hold the EntityManager in a global component, since that would be yet another indirection layer and you can simply mock the EntityManager anyway.
Currently, I'm using PersistenceContext to inject an EntityManager. The EM is injected perfectly.
#Stateless
public StatelessSessionBean implements StatelessSessionBeanLocal {
#PersistenceContext(unitName = "MyPersistenceUnit")
private EntityManager em;
#Override
public Collection<MyObject> getAllObjects(){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriqQuery<MyObject> query = cb.createQuery(MyObject.class);
query.from(MyObject);
return em.createQuery(query).getResultList();
}
}
Now I try to decorate the bean, and suddenly the em doesn't get injected. I get a NullPointerException.
#Decorator
public StatelessSessionBeanDecorator implements StatelessSessionBeanLocal {
#Inject
#Delegate
#Any
StatelessSessionBeanLocal sb
#Override
public Collection<MyObject> getAllObjects(){
System.out.println("Decorated method!");
return sb.getAllObjects();
}
}
I know EJB and CDI are 2 completely different managers, so the one doesn't know about the other. I'm expecting that #PersistenceContext is an EJB injection point, while #Inject is a CDI one. What should I do to solve this and get the EntityManager to be injected like it should?
The best practice for persistence context and CDI is to make them CDI bean to avoid these kind of issue.
public class MyProducers {
#Produces
#PersistenceContext(unitName = "MyPersistenceUnit")
private EntityManager em;
}
After that you'll be able to inject the EntityManager in CDI way. Taking your EJB it'll be :
#Stateless
public StatelessSessionBean implements StatelessSessionBeanLocal {
#Inject
private EntityManager em;
#Override
public Collection<MyObject> getAllObjects(){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriqQuery<MyObject> query = cb.createQuery(MyObject.class);
query.from(MyObject);
return em.createQuery(query).getResultList();
}
}
This way, you'll be able to decorate your CDI bean with no issue.
If you have multiple EntityManagers you can use CDI qualifiers to distinguish them
#PersistenceContext is an EJB injection point, while #Inject is a CDI one
Actually, no. #PersistenceContext annotation can be used in CDI and is not connected with EJB. You can do something like this:
#Named
public class EntityDAO {
#PersistenceContext
private EntityManager manager;
...
}
EJB uses #EJB annotation to inject other EJB, but it can inject any CDI bean or persistence context with same annotations.
I am currently trying to figure out the best way to get a entity manager and a usertransaction in my application.
In JBoss 5.1 I was able to inject it directly into the JSP file, but this is not permitted anymore:
<%!#PersistenceContext(unitName = "unitname")
public EntityManager em;
#Resource
UserTransaction utx;
%>
I have to access em and utx from different locations in my application such as Servlets and Controller classes. So it would be great to have it in one place and to access it globally, but I did not figure out yet how to do it. Any hint would be appreciated.
I found out how to get the EntityManager and the UserTransaction in Servlets, Controller Classes and JSP files.
Let's start with SessionBeans. I redefined all my controller classes as Stateless SessionBeans. Session Beans allow ressource injection. This is how I did it:
#Stateless
public class UserHandling {
#PersistenceContext(unitName = "SSIS2")
private static EntityManager em;
#Resource
private UserTransaction utx;
public User getUser(int userId) {
User userObject = em.find(User.class, userId);
return userObject;
}
}
If another Session Bean is needed in a Session Bean Class, it can be injected with the #EJB annotation:
#Stateless
public class UserHandling {
#PersistenceContext(unitName = "SSIS2")
private static EntityManager em;
#Resource
private UserTransaction utx;
#EJB
UserHandling uh; RoleHandling rh;
public User getUser(int userId) {
User userObject = em.find(User.class, userId);
return userObject;
}
}
In JSP files, you can get the Session Bean Controller classes by lookup the InitialContext:
<%
InitialContext ic = new InitialContext();
UserHandling uh = (UserHandling) ic.lookup("java:app/" + application.getContextPath() + "/UserHandling");
%>
The Issue being Solved
Servlets and JSPs must be stateless because they are shared across multiple threads. An EntityManager does keep state, and so a single instance cannot be shared by concurrent threads.
We'd like a smooth/seamless mechanism for obtaining an EntityManager, preferably managed by the Servlet container.
Servlet-Container Managed Persistence Context
Let's introduce a ContainerManagedPersistenceContext into the Servlet/JSP runtime.
We'll define it in a moment. Let's first look at how it can be used to inject an EntityManager into JSP:
<%! #Inject
#ContainerManagedPersistenceContext.Qualifier
public EntityManager em;
%>
or, better yet into a controller (because we do want to separate data recovery/business logic from our JSP, right?):
#Named
#SessionScoped
public class SessionController implements Serializable
{
...
#Inject
#ContainerManagedPersistenceContext.Qualifier
private EntityManager em;
}
But I don't (yet) have CDI available
If you don't have CDI, but you do have JSF, then the context can be injected as an old-style standard JSF #ManagedProperty:
#Named
#SessionScoped
public class SessionController implements Serializable
{
...
#ManagedProperty(value = "#{containerManagedPersistenceContext}")
ContainerManagedPersistenceContext cmpContext;
...
public void myMethod() {
EntityManager em = cmpContext.getEntityManager();
try {
...
} finally {
em.close();
}
}
}
Remember that - for all the same reasons that we have to go to this effort in the first place - the EntityManager must never be cached/preserved anywhere.
Transactions
Use the EntityTransaction provided by the EntityManager for begin/commit/rollback:
EntityTransaction transaction = em.getTransaction();
ContainerManagedPersistenceContext
This is defined as an application scoped controller and a PersistenceContext:
#PersistenceContext(name = ContainerManagedPersistenceContext.NAME,
unitName = ContainerManagedPersistenceContext.UNIT_NAME)
#ApplicationScoped
public class ContainerManagedPersistenceContext implements Serializable
{
private static final long serialVersionUID = 1L;
// UNITNAME must match persistence.xml: <persistence-unit name="myUnitName">
public static final String UNITNAME = "myUnitName";
public static final String NAME = "persistence/" + UNIT_NAME;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD,
ElementType.PARAMETER, ElementType.TYPE})
public static #interface Qualifier { }
// Servlets must be stateless (shared across multiple threads).
// EntityManager is not stateless (cannot be shared across threads).
// Obtain Container Managed EntityManager - and do NOT cache.
#Produces #Qualifier
public static EntityManager getEntityManager() throws NamingException
{
EntityManager lookup = InitialContext.doLookup("java:comp/env/" + NAME);
return lookup;
}
}
Limitations
As written, this defines a specifically named PersistenceContext for the Servlet container. Since the unitName isn't parameterized, it doesn't provide the level of flexibility as:
#PersistenceContext(unitName = "unitname")
public EntityManager em;
Alternatives
Define a PersistenceContext on your Servlet, and use JNDI name lookup.
Well i think you should see the problem from a different point of view?
Why do you need to call an EJB from JSP page?
JSP page shouldn't contain codes and it is used only for presentation.
I suggest to you to add a Servlet or a JSF framework and let the Servlet or the ManagedBean to call EJB and then pass the parameters to the JSP.
Hope it helps you
You can use the following snippet to retrieve EntityManager and/or UserTransaction via JNDI lookup:
try {
Context ic = (Context) new InitialContext();
EntityManager em = (EntityManager) ic.lookup("java:comp/env/*<persistence-context-name>*");
UserTransaction ut = (UserTransaction) ic.lookup("java:comp/env/UserTransaction");
} catch (NamingException ne) {...}