JavaEE6:数据库关闭时如何保护Web应用程序 [英] JavaEE6: How to safeguard web application when the database shut down

查看:267
本文介绍了JavaEE6:数据库关闭时如何保护Web应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我的框架是Java EE 6与JSF,托管bean,EJB和JPA。我写了一个简单的程序来查询数据库中的信息。所以当我点击一个按钮时,它会触发一个托管bean的事件,其中一个事件侦听器方法将访问EJB方法。 EJB方法将对实体执行简单的选择查询。如果数据库在我之前或期间我关闭,我选择,我得到一个例外

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

内部异常:com.mysql.jdbc。 exceptions.jdbc4.CommunicationsException:通信链路故障

从服务器成功接收的最后一个数据包是51,460毫秒。发送到服务器的最后一个数据包是0毫秒。
错误代码:0

如何避免此异常?肯定是一个 try,catch 这里,但不知道该放在哪里。当我执行 em.createNamedQuery em.remove 时,我尝试捕获 com.mysql .jdbc.exceptions.jdbc4.CommunicationsException ,但是我有一个错误说:异常com.mysql.jdbc.exceptions.jdbc4.CommunicationsException从不抛出对应的try语句的正文



以下是我的代码,我在哪里可以找到例外?



这是我的 EJB

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

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

这是我的 ManagedBean

  @ManagedBean(name =document)
@ViewScoped
public DisplayListController类实现Serializable {

@EJB
DocumentSBean sBean;

列表<用户> users = null;

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






编辑



我尝试以下两种方式,但仍然返回状态200而不是500的firebug

 < p:commandButton update =myformactionListener =#{document.setDisplayFacility}rendered =#{utility.admin}value =设施 /> 

 < p:commandButton update =myformactionListener =#{document.setDisplayFacility}rendered =#{utility.admin}value =设施> 
< p:ajax actionListener =#{document.setDisplayFacility}update =myformevent =click/>
< / p:commandButton>

这里是setDisplayFacility()

  public void setDisplayFacility(){
facility = sBean.getAllFacilities(); // sBean是EJB
displayFacility = true;
}


解决方案


如何避免这种异常?肯定是一个尝试,赶上这里,但不知道该放在哪里。


只能捕捉到您可以以合理的方式处理的异常。



我试图捕捉到com.mysql.jdbc.exceptions.jdbc4.CommunicationsException,但是我收到一个错误,说:异常com.mysql.jdbc($)


.exceptions.jdbc4.CommunicationsException从不抛出对应的try语句的正文。


CommunicationsException 在这种情况下是 DatabaseException 嵌套异常。 EclipseLink已经覆盖了已经捕获 CommunicationsException 并将其重新推送为 DatabaseException CommunicationsException 作为根本原因。如下所示:

  try {
//执行查询。
} catch(Exception e){
throw new DatabaseException(Internal Exception:+ e,e);
}

理论上,你只能处理它如下:

  try {
//让EclipseLink执行查询。
} catch(DatabaseException e){
if(e.getCause()instanceof CommunicationsException){
//句柄。
}
}

在这种情况下,这是丑陋的,不推荐







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


取决于您希望如何处理异常。如果要在通用错误页面中显示,那么您不应该自己抓住它,而只是让它走。 servletcontainer将自动捕捉并处理它。它将在 web.xml 中查找最匹配的< error-page> 并显示它。

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

这个将显示 /generic-error.xhtml for 子类



如果你想要在特定的错误页面中显示它,则需要声明更具体的< 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> 视图中的组件。尝试向PrimeFaces命令组件添加 ajax =false,最后会看到正在显示的servletcontainer的默认错误页面(或任何一个,如果匹配的 web.xml 被发现)。



如果要在PrimeFaces收到ajax错误时显示一些通用JSF UI,请使用错误 <号码: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 =blockstyleClass =ui-message-error ui-widget ui-corner-all>
< h:outputText value =发生错误! />< br />
< h:outputLink value =#onclick =window.location.reload(true)>< h:outputText value =请重新加载页面并重试/>< / h: outputLink>< br />
< h:outputLink value =mailto:support@example.com?subject = Ajax%20Error>< h:outputText value =如果无效,请联系支持/>< / H:outputLink的>
< / h:panelGroup>
< / f:facet>
< / p:ajaxStatus>

(但有一些错误在PrimeFaces 2.2 RC1中,导致显示错误构面失败,它在PrimeFaces 2.1中正常工作)


First of all, my framework is Java EE 6 with JSF, managed bean, EJB and JPA. I write a simple program to query information from the database. So when I click a button, it trigger an event to a managed bean, where an event listener method will access EJB method. The EJB method will do a simple select query to an Entity. If the database is shutdown before or during the time I select, I get an exception

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

How do I safeguard away from this Exception? Definitely a try, catch here, but not sure where to put it. When I do em.createNamedQuery or em.remove, I try to catch com.mysql.jdbc.exceptions.jdbc4.CommunicationsException, but I got an error said: Exception com.mysql.jdbc.exceptions.jdbc4.CommunicationsException is never thrown in body of corresponding try statement.

Below are my codes, where would I catch the Exception?

This is my EJB

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

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

This is my ManagedBean

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

   @EJB
   DocumentSBean sBean;

   List<User> users = null;

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


EDIT

I try both ways as listed below, but still return status 200 instead of 500 on firebug

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

OR

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

Here is setDisplayFacility()

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

解决方案

How do I safeguard away from this Exception? Definitely a try, catch here, but not sure where to put it.

Only catch the exception there where you can handle it in a reasonable manner.


I try to catch com.mysql.jdbc.exceptions.jdbc4.CommunicationsException, but I got an error said: Exception com.mysql.jdbc.exceptions.jdbc4.CommunicationsException is never thrown in body of corresponding try statement.

The CommunicationsException is in this case a nested exception of DatabaseException. EclipseLink is under the covers already catching the CommunicationsException and rethrowing it as DatabaseException with the CommunicationsException as root cause. Something like:

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

In theory, you can only handle it as follows:

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

Which is however ugly and not recommended in this particular case.


Below are my codes, where would I catch the Exception?

Depends on how you would like to handle the exception. If you want to display it in a generic error page, then you should not catch it yourself, but just let it go. The servletcontainer will then catch and handle it itself. It will lookup the best matching <error-page> in the web.xml and display it.

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

This one will display /generic-error.xhtml for all subclasses of java.lang.Exception.

If you want to display it in a specific error page, then you need to declare the <exception-type> more specific to match the actual exception type. E.g.:

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


However, although not explicitly specified in your question, I know based on your question history that you're using JSF with PrimeFaces. You need to keep in mind that PrimeFaces will not display the error page when the initial request was made by ajax. Instead, its ajax view handler has already catched the exception itself and it will delegate to the <p:ajaxStatus> component in the view. Try adding ajax="false" to the PrimeFaces command component and you'll finally see the servletcontainer's default error page being displayed (or any of yours if a matching one in web.xml is found).

If you want to display some generic JSF UI when PrimeFaces received an ajax error, then use the error facet of <p:ajaxStatus>. E.g.

<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>

(there's however some bug in PrimeFaces 2.2 RC1 which causes displaying the error facet to fail, it works correctly in PrimeFaces 2.1)

这篇关于JavaEE6:数据库关闭时如何保护Web应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆