我有一個基於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