What is the best approach to get EntityManagerFactory in web app(jsp/servlets)?
Is this a good way When should EntityManagerFactory instance be created/opened?,
or is it better to get it from JNDI, or something else?
They're heavyweight and they're supposed to be in the application scope. So, you need to open them on application startup and close them on application shutdown.
How to do that depends on your target container. Does it support EJB 3.x (Glassfish, JBoss AS, etc)? If so, then you don't need to worry about opening/closing them (neither about transactions) at all if you just do the JPA job in EJBs with #PersistenceContext the usual way:
#Stateless
public class FooService {
#PersistenceContext
private EntityManager em;
public Foo find(Long id) {
return em.find(Foo.class, id);
}
// ...
}
If your target container doesn't support EJBs (e.g. Tomcat, Jetty, etc) and an EJB add-on like OpenEJB is also not an option for some reason, and you're thus manually fiddling with creating EntityManagers (and transactions) yourself, then your best bet is a ServletContextListener. Here's a basic kickoff example:
#WebListener
public class EMF implements ServletContextListener {
private static EntityManagerFactory emf;
#Override
public void contextInitialized(ServletContextEvent event) {
emf = Persistence.createEntityManagerFactory("unitname");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
emf.close();
}
public static EntityManager createEntityManager() {
if (emf == null) {
throw new IllegalStateException("Context is not initialized yet.");
}
return emf.createEntityManager();
}
}
(note: before Servlet 3.0, this class needs to be registered by <listener> in web.xml instead of #WebListener)
Which can be used as:
EntityManager em = EMF.createEntityManager();
// ...
Related
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.
The problem is this, I have three EJB, the EJB_A have connection to the server database 1, the EJB_B have connection to the server database 2 and the third EJB_C which is responsible for calling the first two.
When there is an error in the EJB_A or EJB_B only rollback is done in the EJB where there is error, on the other EJB saved properly done, eventhough it should propagate the rollback to the two EJB.
EJB_C:
#Stateless
#LocalBean
#TransactionManagement( TransactionManagementType.BEAN )
public class EJB_C {
private EJB_A ejbA;
private EJB_B ejbB;
#PostConstruct
public void init(){
Context context = null;
try {
context = new InitialContext();
this.ayudanteSessionBean = (AyudanteSessionBean) context.lookup("java:global/Trans1/Trans1DBA/EJB_A");
this.ayudanteSessionBean = (AyudanteSessionBean) context.lookup("java:global/Trans1/Trans1DBA/EJB_B");
} catch (NamingException ex) {
Logger.getLogger(OrquestadorSessionBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void saveTwoEJBs(EntityA, a, EntityB b){
try{
ejbA.save(a);
ejbB.save(b);
}catch (Exception ex) {
}
}
}
EJB_A:
#Stateless
#LocalBean
public class EJB_A {
#PersistenceContext( unitName = "persistA" )
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void guardarAmigo(EntityA a){
em.persist(a);
}
}
EJB_B:
#Stateless
#LocalBean
public class EJB_B {
#PersistenceContext( unitName = "persistB" )
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void guardarAmigo(EntityB b){
em.persist(b);
}
}
Could you help me?
Well, to make it work you will need to setup distributed transactions (XA) properly:
Check that all datasources are XA-ready. Typically this means different jdbc driver class name and different type of connection pool during setup.
The process is vendor-specified, but always described in documentation of your application server.
You need to remove annotation:
#TransactionManagement( TransactionManagementType.BEAN )
to let your container (actually his transaction broker) to manage transactions instead of bean.
3. You need to add #TransactionAttribute annotation on method saveTwoEJBs :
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void saveTwoEJBs(EntityA, a, EntityB b)
It's not required but there is no reason to lookup EJB beans via JNDI context, just inject them via #EJB annotation:
#EJB
private EJB_A ejbA;
#EJB
private EJB_B ejbB;
Some links to go:
http://docs.oracle.com/cd/E13222_01/wls/docs100/ejb30/examples.html
http://docs.oracle.com/cd/E16439_01/doc.1013/e13981/servtran001.htm
http://entjavastuff.blogspot.ru/2011/02/ejb-transaction-management-going-deeper.html
Just out of curiosity, is it possible to directly control an EJB transaction from the Web Container?
To illustrate I made this simple example initiating a UserTransaction in the Web Container(using a Servlet), but the transaction is not bound to the EJB Container (in this case a BMT SFSB).
Why is it? Is there a way to do it?
Stateful Session Bean using BMT
#Stateful
#TransactionManagement(TransactionManagementType.BEAN)
public class CustomerBean implements CustomerBeanLocal{
#PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
#Override
public Integer createCustomer(String name) {
Customer customer = new Customer();
customer.setId(1);
customer.setName(name);
em.persist(customer);
//em.flush();
return customer.getId();
}
}
UserTransaction is initiated in the Servlet, but the Session Bean doesn't persist
The Customer is not persisted to the database.
public class BMTServlet extends HttpServlet {
#EJB
private CustomerBeanLocal customerBean;
#Resource
private UserTransaction userTransaction;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
userTransaction.begin();
customerBean.createCustomer("Tars");
userTransaction.commit();
} catch (Exception e) {
throw new ServletException(e);
}
}
}
If we uncomment the em.flush(); then we get the following exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:792)
org.jboss.ejb3.jpa.integration.JPA1EntityManagerDelegator.flush(JPA1EntityManagerDelegator.java:86)
bean.CustomerBean.createCustomer(CustomerBean.java:25)
BMT will not work in your scenario, as BMT bean will be handling transaction by itself and will not participate in the transaction started in the web module (the container transaction). To control transaction from servlet using UserTransaction, the bean must be CMT.
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.
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) {...}