Как правильно перехватывать, переносить и повторно создавать исключения из режима гибернации?

#java #hibernate #exception

#java #гибернация #исключение

Вопрос:

Мой работник базы данных реализован над режимом гибернации. Если что-то пойдет не так, его методы должны откатить транзакцию и выдать SQLException . Итак, мой вопрос: каков наилучший (т. Е. Самый чистый) способ обработки исключений гибернации? В настоящее время все мои методы выглядят так же уродливо, как это:

 public EntryUserHib addUser(final String username, final String pwdhash) throws SQLException{
    try {
        final Transaction ta = sess.beginTransaction();
        try {
            // Using Hibernate here
            // "return" statement
        } catch(final HibernateException ex) {
            try {
                ta.rollback();
            } catch(final Exception ex1) {}
            throw ex;
        } finally {
            if (!ta.wasRolledBack()) ta.commit();
        }
    } catch(final HibernateException ex) {
        if (ex.getCause() != null) {
            if (ex.getCause() instanceof SQLException) throw (SQLException)ex.getCause();
            throw new SQLException(ex.getCause());
        }
        throw new SQLException(ex);
    }
}
  

Ответ №1:

Не перехватывайте их вообще. Исключения гибернации расширяют исключение RuntimeException по двум веским причинам: вам не нужно объявлять их в сигнатурах методов, и любое исключение RuntimeException автоматически вызывает откат транзакции. Обработка исключений приводит к очень загроможденному коду. У сотрудников Hibernate есть философия, согласно которой исключения HibernateExceptions должны быть фатальными ошибками, сигнализирующими о кодировании или логических ошибках, и в правильно функционирующем приложении не должны быть (и не должны быть) перехвачены.

Однако пользовательский интерфейс вашего приложения должен реагировать на эти сюрпризы удобным для пользователя способом. Это отдельная проблема.

Комментарии:

1. Это серверное приложение без пользовательского интерфейса и множества выполняемых параллельных задач, и ни одна из них не должна наносить вред всему приложению, поэтому мне действительно нужно их перехватывать и повторно выбрасывать объявленным способом. Другой причиной этого является тот факт, что существует три реализации my DatabaseWorker — использование Hibernate, JDBC и simple in-memory model для тестов, и в настоящее время я могу свободно переключать их.

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

Ответ №2:

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

Комментарии:

1. Спасибо, я посмотрю на это, но действительно ли мне нужно использовать фреймворк только для управления исключениями одного класса?

2. Распространенное заблуждение, что Spring — это «всего лишь» фреймворк. В него упакованы тонны повторно используемых библиотек. Например, для вашей ситуации он предлагает TransactionTemplate и HibernateTemplate (как указано ранее), которые делают именно то, что вы просите. Да, вы могли бы написать их самостоятельно, но зачем?