从JSP获取EntityManager和UserTransaction的最佳实践

时间:2012-08-02 08:46:26

标签: java jsp jboss7.x entitymanager

我目前正在尝试找出在我的应用程序中获取实体管理器和usertransaction的最佳方法。

在JBoss 5.1中,我能够将它直接注入到JSP文件中,但不再允许这样做了:

<%!@PersistenceContext(unitName = "unitname")
    public EntityManager em;

    @Resource
    UserTransaction utx;
%>

我必须从我的应用程序中的不同位置访问emutx,例如Servlets和Controller类。因此,将它放在一个地方并在全球范围内访问它会很棒,但我还没弄清楚如何做到这一点。任何提示都将不胜感激。

4 个答案:

答案 0 :(得分:4)

我发现了如何在Servlet,控制器类和JSP文件中获取EntityManager和UserTransaction。

让我们从SessionBeans开始。我将所有控制器类重新定义为无状态SessionBeans。会话Bean允许资源注入。我就这样做了:

@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;
  }
}

如果会话Bean类中需要另一个会话Bean,则可以使用@EJB注释注入它:

@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;
  }
}

在JSP文件中,您可以通过查找InitialContext来获取Session Bean Controller类:

<%
    InitialContext ic = new InitialContext();
    UserHandling uh = (UserHandling) ic.lookup("java:app/" + application.getContextPath() + "/UserHandling");
%>

答案 1 :(得分:4)

正在解决的问题

Servlet和JSP必须是无状态的,因为它们在多个线程之间共享。 EntityManager确实保持状态,因此并发线程无法共享单个实例。

我们想要一个平滑/无缝的机制来获取EntityManager,最好由Servlet容器管理。

Servlet-Container托管持久化上下文

让我们在Servlet / JSP运行时中引入ContainerManagedPersistenceContext

我们稍后会定义它。我们先来看一下如何将EntityManager注入JSP

<%! @Inject
    @ContainerManagedPersistenceContext.Qualifier
    public EntityManager em;
%>

或者,更好地进入控制器(因为我们确实希望将数据恢复/业务逻辑与JSP分开,对吧?):

@Named
@SessionScoped
public class SessionController implements Serializable
{
    ...

    @Inject
    @ContainerManagedPersistenceContext.Qualifier
    private EntityManager em;
}

但我(还)没有CDI可用

如果您没有CDI,但确实有JSF,则可以将上下文注入旧式标准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();
        }
    }
}

请记住 - 出于所有我们必须首先考虑这一努力的原因 - EntityManager绝不能在任何地方缓存/保存。

交易

使用EntityTransaction提供的EntityManager进行开始/提交/回滚:

  

EntityTransaction transaction = em.getTransaction();

ContainerManagedPersistenceContext

这被定义为应用程序作用域控制器和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;
    }
}

限制

如上所述,这为Servlet容器定义了一个特别命名的PersistenceContext。由于unitName未参数化,因此无法提供以下灵活性:

@PersistenceContext(unitName = "unitname")
public EntityManager em;

替代

Define a PersistenceContext on your Servlet, and use JNDI name lookup

答案 2 :(得分:1)

嗯,我认为你应该从不同的角度看问题? 为什么需要从EJB页面拨打JSP

JSP页面不应包含代码,仅用于演示。 我建议您添加ServletJSF framework,让ServletManagedBean调用EJB,然后将参数传递给{{} 1}}。

希望它可以帮到你

答案 3 :(得分:-1)

您可以使用以下代码段通过JNDI查找检索EntityManager和/或UserTransaction:

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