JavaEE6: как защитить веб-приложение при завершении работы базы данных

Прежде всего, мой фреймворк - Java EE 6 с JSF, управляемым компонентом, EJB и JPA. Я пишу простую программу для запроса информации из базы данных. Поэтому, когда я нажимаю кнопку, она вызывает событие для управляемого компонента, где метод прослушивателя событий будет обращаться к методу EJB. Метод EJB сделает простой select запрос к сущности. Если база данных отключена до или во время 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.createNamedQuery или же em.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 в firebug

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

3 ответа

Решение

Как уберечься от этого исключения? Определенно попробуйте, поймайте здесь, но не уверены, где его поставить.

Только ловите исключение там, где вы можете справиться с этим разумным образом.


Я пытаюсь поймать com.mysql.jdbc.exceptions.jdbc4.CommunicationsException, но я получил сообщение об ошибке: Исключение com.mysql.jdbc.exceptions.jdbc4.CommunicationsException никогда не добавляется в тело соответствующего оператора try.

CommunicationsException в этом случае является вложенным исключением DatabaseException, EclipseLink уже находится под прикрытием CommunicationsException и бросить его как DatabaseException с CommunicationsException как первопричина. Что-то вроде:

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

Что, однако, некрасиво и не рекомендуется в данном конкретном случае.


Ниже приведены мои коды, где бы я поймал исключение?

Зависит от того, как вы хотели бы обработать исключение. Если вы хотите отобразить его на общей странице ошибок, то вам не следует ловить его самостоятельно, а просто отпустить. Контейнер-сервлет сам поймает и обработает его. Это будет искать лучшее соответствие <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. Вы должны иметь в виду, что PrimeFaces не будет отображать страницу с ошибкой, когда первоначальный запрос был сделан ajax. Вместо этого его обработчик представления ajax уже перехватил само исключение и передаст его <p:ajaxStatus> Компонент в представлении. Попробуйте добавить ajax="false" к компоненту команды PrimeFaces, и вы, наконец, увидите страницу с ошибкой сервлетконтейнера по умолчанию (или любую вашу, если она совпадает с web.xml найден).

Если вы хотите отобразить некоторый универсальный пользовательский интерфейс JSF, когда PrimeFaces получил ошибку AJAX, используйте 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 он работает правильно)

CommunicationException заключено в EclipseLink DatabaseException, которое является исключением времени выполнения. Если вы используете JPA или JTA, то это также может быть включено в PersistenceException или TransactionRolledbackException. Итак, попробуйте перехватить одно из них или исключение RuntimeException в худшем случае. CommunicationsException будет в вызванной цепью.

EclipseLink автоматически попытается восстановить неработающие соединения, но если ваша база данных не работает, это не удастся (вы можете увидеть ошибку, зарегистрированную 3 раза), поэтому вам нужно будет сообщить об ошибке своему пользователю.

На мой взгляд, по крайней мере, недоступность базы данных является серьезной ошибкой, которую нужно обработать, и обычно КАК МОЖНО СКОРЕЕ. Общий подход к защите от такой ситуации заключается в применении механизмов высокой доступности и аварийного переключения через кластеризацию базы данных.

Однако если у вас нет этой опции, и вы не хотите, чтобы пользователь видел исключение с большим содержанием жира, вы можете попробовать направить его на какую-то удобную для пользователя страницу, когда произойдет эта конкретная ошибка. Для этого поместите в ваш 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 общий подход состоит в том, чтобы поместить некоторое удобное для пользователя и в основном извиняющееся сообщение, указывающее, как администратор сожалеет о неудобствах для пользователя...

Во всяком случае, работа с такими ситуациями путем перехвата исключений и не воздействия на них, либо перебрасыванием, либо обработкой их в блоке перехвата, если это возможно, обычно считается плохой практикой, когда критические ошибки могут остаться незамеченными.,

Что касается вашего вопроса "никогда не добавляется в тело соответствующего оператора try", вы можете проверить эту статью.

Ура!

Другие вопросы по тегам