我有一个基于JSF 2 @ViewScoped
的web应用程序,我不能让事务正确地进行,或者说:它们根本不会启动。无法启动JSF @ViewScoped @Stateless bean
我也使用Java EE 6的CDI和EJB3。
这里的主要豆:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
...
@ManagedBean
@ViewScoped
@Stateless
public class PqManager implements Serializable
{
private List<PqListItem> pqItems;
@Inject
private PqService pqService;
public List<PqListItem> getPqItems()
{
if (pqItems == null)
{
pqItems = pqService.findActivePqs();
}
return pqItems;
}
...
}
视图作用域的bean从JSF页面用来显示一个DataTable一个简单的列表。由于它具有基于AJAX的操作来添加项目,移除项目并通过RichFaces(过滤)对其进行排序,因此它被视为范围。
我为每个启动事务的方法调用添加了@Stateless
(或者如果不存在,则创建一个新的,默认值为TransactionAttributeType.REQUIRED
)。这个想法来自于“核心JavaServer Faces,第三版”一书,但是我还没有找到任何能够匹配我自己的例子。
注入PQSERVICE类(它不会有所作为使用@EJB
代替):
@Stateless
public class PqService extends JpaCrudService
{
...
public List<PqListItem> findActivePqs()
{
return em.createQuery("SELECT NEW ... whatever not interesting here... WHERE pq.workflow = '" + Workflow.ACTIVE + "' GROUP BY pq.id", PqListItem.class).getResultList();
}
...
}
JpaCrudService(基本上是从亚当边的例子http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao拍摄):
//@Stateless
//@Local(CrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public abstract class JpaCrudService implements CrudService
{
@PersistenceContext(unitName = "PqGeneratorPu")
protected EntityManager em;
@Override
public <T> T create(T t)
{
em.persist(t);
em.flush();
em.refresh(t);
return t;
}
...
}
唯一的区别是我的子类JpaCrudService
,因为我不喜欢查询存储在/在实体。所以我省略了@Local
注释(纠正我,如果这是错误的)。 @Stateless
不是继承AFAIK,我只注入子类,所以我也评论说一个。
这就是说,豆,然后从一个JSF页面访问:
<rich:dataTable value="#{pqManager.pqItems}"
var="pq">
<f:facet name="header">
<h:outputText value="Active" />
</f:facet>
...
然而,在加载页面时,我得到一个异常:
javax.ejb.EJBTransactionRequiredException: Transaction is required for invocation: [email protected]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.mandatory(CMTTxInterceptor.java:255)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:184)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.as.ee.component.TCCLInterceptor.processInvocation(TCCLInterceptor.java:45)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:165)
at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:173)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288)
at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:72)
at de.company.webapp.service.PqService$$$view95.findActivePqsFor(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:264)
at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:52)
at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:137)
at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:260)
at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:111)
at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105)
at de.company.webapp.service.PqService$Proxy$_$$_Weld$Proxy$.findActivePqs(PqService$Proxy$_$$_Weld$Proxy$.java)
at de.company.webapp.facade.PqManager.getPqItems(PqManager.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
.
.
.
它失败,因为调用pqService.findActivePqsFor()
没有按在现有交易中运行(TransactionAttributeType.MANDATORY
,其中是继承AFAIK的)。
请注意,通过删除JpaCrudService
上的TransactionAttributeType.MANDATORY
并使用扩展的实体管理器,可以正确显示页面而不使用事务处理,但这仅用于测试目的。
但是,为什么不能正常工作?为什么交易不在这里开始? JSF @ViewScoped
bean有什么?不相容?
如何修复?
PS:我正在使用JBoss AS 7.1.1。
谢谢。Seam 3面临我正在寻找的解决方案吗?我终于想知道其他人如何在没有CDI的普通Java EE 6中从这样的@ViewScoped bean获取事务。这将如何工作/看起来像? – Kawu 2012-04-22 00:25:57
是的,它可以工作,但是,Seam 3没有被积极开发。工作正在进入DeltaSpike,但我们尚未解决JSF问题。至于另一个问题,您将为UserTransaction执行JNDI查找并手动处理事务边界。 – LightGuard 2012-04-23 03:44:14
那么,现在我只需要一个解决方案,可以开始交易**。我会继续关注DeltaSpike,请参阅http://www.infoq.com/news/2012/04/seam-deltaspike。感谢这个顶级信息! – Kawu 2012-04-23 10:36:30