Best practice to get EntityManger and UserTransaction from JSP

若如初见. 提交于 2019-12-21 05:45:23

问题


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.


回答1:


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");
%>



回答2:


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.




回答3:


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




回答4:


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) {...}


来源:https://stackoverflow.com/questions/11773975/best-practice-to-get-entitymanger-and-usertransaction-from-jsp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!