2

首先,我的框架是带有 JSF、托管 bean、EJB 和 JPA 的 Java EE 6。我编写了一个简单的程序来从数据库中查询信息。因此,当我单击一个按钮时,它会触发一个托管 bean 的事件,其中事件侦听器方法将访问 EJB 方法。selectEJB 方法将对实体进行简单查询。如果数据库在 I 之前或期间关闭select,则会出现异常

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DatabaseException

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 51,460 milliseconds ago.  The last packet sent successfully to the server was 0 milliseconds ago.
Error Code: 0

如何避免此异常?绝对是try, catch这里,但不知道放在哪里。当我做em.createNamedQueryorem.remove时,我尝试捕捉com.mysql.jdbc.exceptions.jdbc4.CommunicationsException,但我得到一个错误说:Exception com.mysql.jdbc.exceptions.jdbc4.CommunicationsException is never thrown in body of corresponding try statement

以下是我的代码,我将在哪里捕获异常?

这是我的EJB

@Stateless
@LocalBean
public class DocumentSBean {
    @PersistenceContext
    private EntityManager em;

    public List<User> listUser(){
         Query query = em.createNamedQuery("User.listUser");
         query.returnResultList();
    }
}

这是我的ManagedBean

@ManagedBean(name="document")
@ViewScoped
public class DisplayListController implements Serializable {            

   @EJB
   DocumentSBean sBean;

   List<User> users = null;

   public void foo(){
       users = sBean.listUser();
   }
}

编辑

我尝试了下面列出的两种方式,但仍然在萤火虫上返回状态 200 而不是 500

<p:commandButton update="myform" actionListener="#{document.setDisplayFacility}" rendered="#{utility.admin}" value="Facilities"/>

或者

<p:commandButton update="myform" actionListener="#{document.setDisplayFacility}" rendered="#{utility.admin}" value="Facilities">
       <p:ajax actionListener="#{document.setDisplayFacility}" update="myform" event="click"/>
</p:commandButton>

这是 setDisplayFacility()

public void setDisplayFacility(){
   facilities = sBean.getAllFacilities(); //sBean is EJB
   displayFacility = true;
}
4

3 回答 3

6

如何避免此异常?绝对是一个尝试,抓住这里,但不知道把它放在哪里。

只在可以合理处理的地方捕获异常。


我尝试捕获 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException,但我收到一条错误消息:异常 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException 在相应的 try 语句的主体中永远不会抛出。

CommunicationsException在这种情况下,是 的嵌套异常DatabaseException。EclipseLink 在幕后已经捕获并CommunicationsException重新抛出它作为根本原因。就像是:DatabaseExceptionCommunicationsException

try {
     // Execute query.
} catch (Exception e) {
     throw new DatabaseException("Internal Exception: " + e, e);
}

理论上,只能这样处理:

try {
     // Let EclipseLink execute query.
} catch (DatabaseException e) {
    if (e.getCause() instanceof CommunicationsException) {
        // Handle.
    }
}

然而,这很丑陋,在这种特殊情况下不推荐。


以下是我的代码,我将在哪里捕获异常?

取决于您希望如何处理异常。如果您想在通用错误页面中显示它,那么您不应该自己捕获它,而只是让它消失。然后 servlet 容器将自己捕获并处理它。它将在 中查找最佳匹配<error-page>web.xml显示它。

<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/generic-error.xhtml</location>
</error-page>

这将显示/generic-error.xhtml为 的所有子类java.lang.Exception

如果你想在特定的错误页面中显示它,那么你需要声明<exception-type>更具体的以匹配实际的异常类型。例如:

<error-page>
    <exception-type>org.eclipse.persistence.exceptions.DatabaseException</exception-type>
    <location>/database-error.xhtml</location>
</error-page>

但是,尽管您的问题中没有明确指定,但根据您的问题历史,我知道您正在使用 JSF 和PrimeFaces。您需要记住,当 ajax 发出初始请求时,PrimeFaces不会显示错误页面。相反,它的 ajax 视图处理程序本身已经捕获了异常,并将委托给<p:ajaxStatus>视图中的组件。尝试添加ajax="false"到 PrimeFaces 命令组件,您最终会看到正在显示的 servletcontainer 的默认错误页面(如果web.xml找到匹配的错误页面,则为您的任何页面)。

如果您想在 PrimeFaces 收到 ajax 错误时显示一些通用 JSF UI,请error使用<p:ajaxStatus>. 例如

<p:ajaxStatus>
    <f:facet name="start"><h:graphicImage value="images/ajax-loader.gif" /></f:facet>
    <f:facet name="success"><h:outputText value="" /></f:facet>
    <f:facet name="error">
        <h:panelGroup layout="block" styleClass="ui-message-error ui-widget ui-corner-all">
            <h:outputText value="An error has occurred!" /><br />
            <h:outputLink value="#" onclick="window.location.reload(true)"><h:outputText value="Please reload page and retry" /></h:outputLink><br />
            <h:outputLink value="mailto:support@example.com?subject=Ajax%20Error"><h:outputText value="If in vain, please contact support" /></h:outputLink>
        </h:panelGroup>
    </f:facet>
</p:ajaxStatus>

(然而,PrimeFaces 2.2 RC1 中有一些错误会导致显示错误方面失败,它在 PrimeFaces 2.1 中可以正常工作)

于 2010-11-16T19:58:38.977 回答
2

至少在我看来,数据库变得不可用是一个需要处理的严重错误,通常需要尽快处理。防止这种情况的一般方法是通过数据库集群实施高可用性和故障转移机制。

但是,如果您没有此选项,也不希望用户看到大异常,那么您可能会尝试在发生此特定错误时将他路由到一些用户友好的页面。为此,请将以下内容放入您的 web.xml(假设您的 FacesServlet 映射到 *.faces):

<error-page>
    <exception-type>com.mysql.jdbc.exceptions.jdbc4.CommunicationsException</exception-type>
    <location>/errors/error.faces</location>
</error-page>

然后,在 error.xhtml 页面中,一般的方法是放置一些用户友好且很大程度上表示歉意的消息,表明管理员对用户的不便感到多么抱歉......

无论如何,通过捕获异常而不对它们采取行动来处理这种情况,无论是通过重新抛出它们还是在 catch 块中处理它们 - 如果可能的话,通常被认为是一种不好的做法,因为关键错误可能会被忽视.

关于您的“从未在相应的 try 语句正文中抛出”问题,您可能需要查看这篇文章。

干杯!

于 2010-11-10T17:05:20.980 回答
2

CommunicationsException 包装在 EclipseLink DatabaseException 中,这是一个运行时异常。如果您使用的是 JPA 或 JTA,那么这也可能包含在 PersistenceException 或 TransactionRolledbackException 中。所以,试着捕捉其中之一,或者最坏的情况 RuntimeException。CommunicationsException 将在由链引起。

EclipseLink 会自动尝试重新连接死连接,但是如果您的数据库已关闭,这将失败(您可能会看到错误记录了 3 次),因此您需要向您的用户报告错误。

于 2010-11-11T13:45:02.197 回答