Где принадлежит аннотация @Transactional?

Следует ли размещать @Transactional в классах DAO и/или их методах или лучше комментировать классы службы, которые вызывают с использованием объектов DAO? Или имеет смысл аннотировать оба "слоя"?

+429
источник поделиться
18 ответов

Я думаю, что транзакции принадлежат слою службы. Это тот, который знает об единицах работы и случаях использования. Это правильный ответ, если у вас несколько DAO, введенных в Службу, которые должны работать вместе в одной транзакции.

+443
источник

В целом я согласен с другими, заявляя, что транзакции обычно начинаются на уровне обслуживания (в зависимости от требуемой детализации).

Однако в то же время я также начал добавлять @Transactional(propagation = Propagation.MANDATORY) к моему уровню DAO (и другим уровням, которым не разрешено запускать транзакции, но требуются существующие), потому что гораздо легче обнаружить ошибки, в которых вы забыли начать транзакция в вызывающем абоненте (например, услуга). Если ваш DAO аннотируется с обязательным распространением, вы получите исключение, указав, что при вызове метода нет активной транзакции.

У меня также есть тест интеграции, где я проверяю все beans (bean пост-процессор) для этой аннотации и терпит неудачу, если существует аннотация @Transactional с распространением, отличным от Mandatory, в bean, которая не принадлежит на уровень услуг. Таким образом, я уверен, что мы не запускаем транзакции на неправильном уровне.

+260
источник
другие ответы

Связанные вопросы


Похожие вопросы

Транзакционные аннотации должны быть размещены вокруг всех операций, которые неотделимы.

Например, ваш вызов - "сменить пароль". Это состоит из двух операций

  • Измените пароль.
  • Аудит изменений.
  • Отправляйте клиенту сообщение о том, что пароль был изменен.

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

Вот те вопросы, которые вам нужно задать при выборе места @Transactional.

+74
источник

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

Новая тенденция в Spring относится к доменному проекту (DDD). Spring Roo отлично иллюстрирует тенденцию. Идея состоит в том, чтобы сделать объект POJO домена более более богатым, чем на типичных архитектурах Spring (обычно они anemic) и, в частности, поставить семантику транзакций и персистентности на объекты домена. В тех случаях, когда все, что требуется, - это простые операции CRUD, веб-контроллеры работают непосредственно над объектами POJO домена (они функционируют как сущности в этом контексте), и нет уровня обслуживания. В случаях, когда между объектами домена требуется некоторая координация, вы можете иметь дескриптор службы bean, который с @Transaction согласно традиции. Вы можете настроить распространение транзакций на объектах домена на нечто вроде REQUIRED, чтобы объекты домена использовали любые существующие транзакции, такие как транзакции, запущенные в службе bean.

Технически этот метод использует AspectJ и <context:spring-configured />. Roo использует определения Inter-type AspectJ для разделения семантики объекта (транзакций и персистентности) на предмет объектов домена (в основном на поля и бизнес-методы).

+37
источник

Нормальным случаем будет аннотация на уровне уровня сервиса, но это действительно зависит от ваших требований.

Аннотирование на уровне сервиса приведет к более длительным транзакциям, чем аннотирование на уровне DAO. В зависимости от уровня изоляции транзакций, который может вызывать проблемы, поскольку параллельные транзакции не видят друг друга, например, напр. ПОВТОРНОЕ ПРОЧИТАНИЕ.

Аннотирование по DAO будет держать транзакции как можно короче, с недостатком того, что функциональность, которую ваш уровень обслуживания обнажает, не будет выполняться в одной транзакции (откатной).

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

+36
источник

Я размещаю @Transactional на уровне @Service и устанавливаю rollbackFor любое исключение и readOnly для дальнейшей оптимизации транзакции.

По умолчанию @Transactional будет искать только RuntimeException (Unchecked Exceptions), установив rollback на Exception.class (Checked Exceptions), он откатится для любого исключения.

@Transactional(readOnly = false, rollbackFor = Exception.class)

См. Проверенные или непроверенные исключения.

+24
источник

Или имеет смысл аннотировать оба "слоя"? - не имеет смысла аннотировать как уровень сервиса, так и уровень dao - если вы хотите убедиться, что метод DAO всегда вызываемый (распространяемый) из служебного уровня с "обязательным" распространением в DAO. Это обеспечит некоторое ограничение для того, чтобы методы DAO вызывались из уровня пользовательского интерфейса (или контроллеров). Кроме того, когда модульное тестирование уровня DAO, в частности, с аннотацией DAO, также гарантирует, что оно проверено на функциональность транзакций.

+17
источник

Кроме того, Spring рекомендует использовать только аннотацию для конкретных классов, а не интерфейсов.

http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

+15
источник

Как правило, на сервисный уровень следует поместить транзакцию.

Но, как указывалось ранее, атомарность операции - это то, что говорит нам о необходимости аннотации. Таким образом, если вы используете фреймворки, такие как Hibernate, где одна операция "сохранить/обновить/удалить/..." на объекте может изменить несколько строк в нескольких таблицах (из-за каскада через граф объектов), Конечно, также должно быть управление транзакциями по этому конкретному методу DAO.

+12
источник

Для транзакции на уровне базы данных

в основном я использовал @Transactional в DAO только на уровне метода, поэтому конфигурация может быть специально для метода/с использованием по умолчанию (требуется)

  • Метод DAO, который получает выборку данных (выберите...) - не нужен @Transactional Это может привести к некоторым накладным расходам из-за перехватчик транзакций/и прокси-сервер AOP, которые необходимо выполнить как хорошо.

  • Методы DAO, которые вставляют/обновляют, получат @Transactional

очень хороший блог на трансформальный

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

@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){

    try {    
        //service logic here     
    } catch(Throwable e) {

        log.error(e)
        throw new MyApplicationException(..);
    }
}
+12
источник

Лучше иметь его в сервисном слое! Это ясно объясняется в одной из статей, которые я встретил вчера! Вот ссылка, которую вы можете проверить!

+7
источник

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

Итак, давайте возьмем пример:

У нас есть 2 модели, т.е. Country и City. Реляционное сопоставление моделей Country и City похоже на одно Country может иметь несколько городов, так что отображение похоже на

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

Здесь Страна сопоставлена ​​с несколькими городами с их выборкой Lazily. Итак, вот роль @Transactinal, когда мы извлекаем объект Country из базы данных, тогда мы получим все данные объекта Country, но не получим Set of cities, потому что мы выбираем города Lazily.

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

Когда мы хотим получить доступ к Set of Cities из объекта страны, тогда мы получим нулевые значения в этом Set, потому что объект Set, созданный только этим Set, не инициализируется с данными для получения значений Set, которые мы используем @Transactional, т.е.

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

Таким образом, в основном @Transactional служба может выполнять множественный вызов в одной транзакции без закрытия соединения с конечной точкой.

+4
источник

В идеале, уровень сервиса (менеджер) представляет вашу бизнес-логику и, следовательно, он должен быть аннотирован с помощью @Transactional. Уровень сервиса может вызывать разные DAO для выполнения операций БД. Давайте рассмотрим ситуации, в которых у вас есть N число операций DAO в методе службы. Если ваша первая операция DAO не удалась, другие могут быть переданы, и вы закончите несогласованное состояние БД. Уровень аннотирования сервисов может спасти вас от таких ситуаций.

+3
источник

Прежде всего, определим, где мы должны использовать транзакцию?

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

Хорошо известно, что бизнес-логика вводится в сервисы. Таким образом, методы обслуживания могут содержать различные действия, которые должны выполняться как единая логическая единица работы. Если это так - тогда такой метод должен быть отмечен как Транзакционный. Конечно, не каждый метод требует такого ограничения, поэтому вам не нужно отмечать весь сервис как транзакционный.

И даже больше - не забудьте принять во внимание, что @Transactional, очевидно, может снизить производительность метода. Чтобы увидеть всю картину, вам нужно знать уровни изоляции транзакций. Знание этого может помочь вам избежать использования @Transactional, где это не обязательно.

+3
источник

Я предпочитаю использовать @Transactional на уровне сервиса на уровне метода.

+1
источник

@Transactional используется в слое службы, который вызывается с использованием уровня контроллера (@Controller) и вызова уровня обслуживания на уровне DAO (@Repository). Операция, связанная с базой данных.

+1
источник

Сервисный уровень - лучшее место для добавления аннотаций @Transactional в качестве основной части бизнес-логики, присутствующей здесь, и содержит поведение прецедента в уровне детализации.

Предположим, мы добавим его в DAO и из сервиса, который мы вызываем 2 класса DAO, один неудачный и другой успех, в этом случае, если @Transactional не на службе одна БД будет фиксация, а другая будет отката.

Следовательно, моя рекомендация использует эту аннотацию мудро и используется только на уровне сервиса.

Проект Github-java-algos

+1
источник

введите описание изображения здесь

@Transactional следует использовать на уровне сервиса, так как он содержит бизнес-логику. Уровень DAO обычно имеет только операции CRUD базы данных.

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос