4

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

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

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

    @Resource
    UserTransaction utx;
%>

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

4

4 回答 4

4

正在解决的问题

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

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

Servlet-容器托管持久化上下文

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

我们稍后会定义它。让我们首先看一下如何使用它来注入EntityManagerin 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绝不能在任何地方缓存/保存。

交易

使用for begin/commit/rollbackEntityTransaction提供的:EntityManager

EntityTransaction 交易 = 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;

备择方案

在 Servlet 上定义 PersistenceContext,并使用 JNDI 名称查找

于 2012-08-12T00:11:07.717 回答
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;
  }
}

如果 Session Bean Class 中需要另一个 Session 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");
%>
于 2012-08-07T09:13:53.073 回答
1

好吧,我认为您应该从不同的角度看待问题?为什么需要调用EJB来自JSP页面?

JSP页面不应包含代码,它仅用于演示。我建议你添加一个Servlet或一个JSF framework并让ServletManagedBean调用EJB然后将参数传递给JSP

希望对你有帮助

于 2012-08-08T14:34:05.120 回答
-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) {...}
于 2012-08-02T09:00:57.987 回答