目前我正在试图找出让一个实体管理器,并在我的应用程序一个UserTransaction的最佳途径。
在JBoss的5.1我能直接注射到JSP文件中,但这不再允许:
<%!@PersistenceContext(unitName = "unitname")
public EntityManager em;
@Resource
UserTransaction utx;
%>
我访问em
和utx
在我的应用程序,如Servlet和控制器类不同的位置。 因此,这将是巨大的,有它在一个地方,并在全球范围内访问它,但我也没弄明白怎么还没有做到这一点。 任何暗示将不胜感激。
我发现了如何获得的EntityManager和UserTransaction的Servlet中,控制器类和JSP文件。
让我们先从SessionBeans。 我重新定义了我所有的控制器类为无状态SessionBeans。 会话Bean允许的ressource注射。 这是我做的:
@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的获取会话Bean控制器类:
<%
InitialContext ic = new InitialContext();
UserHandling uh = (UserHandling) ic.lookup("java:app/" + application.getContextPath() + "/UserHandling");
%>
该问题正在解决
因为他们在多个线程共享Servlet和JSP必须是无状态的。 一个EntityManager
不保持状态,所以单个实例不能并发线程共享。
我们希望获得一个EntityManager,优选由Servlet容器管理的平滑/无缝机制。
Servlet的容器管理的持久化上下文
让我们引入ContainerManagedPersistenceContext
到servlet / JSP运行。
我们将在稍后定义它。 让我们先来看看它如何被用来注入一个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交易= 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名称查找 。
嗯,我想你应该从不同的角度看这个问题? 为什么你需要调用EJB
从JSP
页面?
JSP
页面不应该包含的代码,它仅用于演示。 我建议你添加Servlet
或JSF framework
,让Servlet
或ManagedBean
调用EJB
,然后将参数传递给JSP
。
希望它可以帮助你
您可以使用下面的代码片段通过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) {...}