Следует ли использовать em.flush в DAO EJB 3.0 для абстрагирования персистентного слоя? - PullRequest
0 голосов
/ 21 марта 2011

Скажем, у меня есть следующий общий dao, развернутый как локальный SLSB:

public interface CrudService {

public <T> T create(T t);

public <T> T find(Object id, Class<T> type);

public <T> T update(T t);

public void delete(Object t);

public List<Object> findByNamedQuery(String queryName);

public List<Object> findByNamedQuery(String queryName, int resultLimit);

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters);

public List<Object> findByNamedQuery(String namedQueryName, Map<String, Object> parameters, int resultLimit);

}

Этот DAO используется во многих других сервисах SLSB.Я хотел бы абстрагировать весь слой постоянства (все операции и исключения) от бизнес-логики.Я создал перехватчик с помощью метода @AroundInvoke, как показано ниже, и поместил его на уровень класса DAO:

    @AroundInvoke
public Object wrapExceptions(InvocationContext context) throws Exception {
    try {
            return context.proceed();           
    } catch(Exception e) {
              throw mapToApplicationException(e)
    }
}

Никаких исключений не было получено, и поэтому он отображен с реализациями по умолчанию методов dao.Но если я использую flush в конце методов persist, update и delete, это работает - и это нормально.

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

Редактировать: другой вариант - использовать BMT, но он вызывает загрязнение всех методов фасада с помощью tx.begin () и т.д ...

РЕДАКТИРОВАТЬ после ответа Криса Бабича:

У меня есть некоторые сомнения по предложению Криса.Работа с PersisteceException в сервисном слое вызывает смешивание прозрачности слоев.Но это не самое страшное для меня.Скажите, что у меня есть Service Facade, использующий набор моих услуг или DAO.Метод Service Facade должен быть выполнен в его собственной транзакции, поэтому я бы использовал CMT и пометил его @TransactionAttribute (REQUIRES_NEW).В этом случае нет места для точки обработки исключений (перехватчик не будет работать, потому что транзакция все еще продолжается - это тот же случай, что и выше).Поэтому я вижу два пути: либо использовать все методы фасадов, использующие BMT, и обрабатывать все вещи tx.begin (), tx.commit () и т. Д., Либо использовать другой «Фасад для фасада» с @TransactionAttribute (NEVER), а затем вызватьТранзакционный фасад и обработка его исключений.

1 Ответ

0 голосов
/ 24 марта 2011

Я думаю, все зависит от того, что вы пытаетесь сделать. Если вы ожидаете, что все данные будут немедленно вставлены в базу данных, и любые проблемы, вызванные этой вставкой, будут немедленно доступны, то у вас действительно есть только два варианта: в частности, вызовите flush () для EntityManager, который приведет к тому, что все операции пакетного источника данных будут или указать, что транзакция должна начинаться и заканчиваться в методе DAO (для этого есть разные варианты, но я не буду здесь их рассматривать). Обе эти опции могут отрицательно сказаться на производительности и успешном определении бизнес-транзакций.

Одной из особенностей реализации JPA является идея PersistenceContext. PersistenceContext - это набор управляемых сущностей. Жизненный цикл этих объектов управляется EntityManager. Часть ответственности EntityManager заключается в управлении, когда изменения в PersistenceContext синхронизируются с источником данных. Возможно, что EntityManager объединяет ряд изменений в PersistenceContext и синхронизирует их на более позднем этапе, например, во время фиксации транзакции. В этом случае, если есть проблема с данными, вставляемыми в базу данных, вы можете не увидеть возникновение исключения до некоторого времени спустя. Вызов em.flush () вызывает немедленную синхронизацию источника данных, что, в свою очередь, вызывает любые исключения, которые могут возникнуть во время этой вставки базы данных.

Один хороший подход к обработке исключений - добавлять его только там, где вам это нужно. Добавление его в метод нижнего уровня, который выбрасывает RuntimeExceptions, не обязательно является хорошим кандидатом. Если идея заключается в добавлении последовательной обработки ошибок, такой как преобразование в обычное RuntimeException, то вы можете сделать это в общей точке входа, такой как бизнес-уровень или аналогичный. Это позволяет вам ограничить общий объем обработки исключений, который вам нужно поддерживать, тем более что ошибки могут действительно возникать в любом месте приложения. Я также хотел бы предложить, чтобы у вас была обработка исключений в ваших основных точках входа транзакции, так как именно здесь вам нужно будет обработать любое непредвиденное исключение, которое может возникнуть только во время фиксации транзакции, особенно при использовании оптимистической блокировки.

Просто некоторые мысли, надеюсь, они помогут.

...