我目前正在尝试找出在我的应用程序中获取实体管理器和usertransaction的最佳方法。
在JBoss 5.1中,我能够将它直接注入到JSP文件中,但不再允许这样做了:
<%!@PersistenceContext(unitName = "unitname")
public EntityManager em;
@Resource
UserTransaction utx;
%>
我必须从我的应用程序中的不同位置访问em
和utx
,例如Servlets和Controller类。因此,将它放在一个地方并在全球范围内访问它会很棒,但我还没弄清楚如何做到这一点。任何提示都将不胜感激。
答案 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 / 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,但确实有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();
这被定义为应用程序作用域控制器和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
页面不应包含代码,仅用于演示。
我建议您添加Servlet
或JSF framework
,让Servlet
或ManagedBean
调用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) {...}