Зачем использовать @Transactional с @Service вместо @Controller

Я видел много комментариев в статьях с переполнением стека. Я нашел некоторые вещи о @Transactional с @Service или с @Controller

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

"Нормальным случаем будет аннотация на уровне уровня обслуживания"

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

Недостаток использования @transactional с уровнем @service

Если у меня было 2 метода, например saveUser() и saveEmail() (потому что я хранил электронные письма в базе данных для их отправки позже - как очередь), я бы создал в своей службе метод saveUserAndSendEmail (Пользователь пользователя), который бы быть транзакционным. [Источник]

Это означает, что я создаю много методов на уровне службы вместо одного Сохранить общий метод, как следует

public <T> long save(T entity) throws DataAccessException {
    Session session = sessionFactory.getCurrentSession();
    long getGenVal=(Long) session.save(entity);
    return getGenVal;
}

В соответствии с приведенным выше решением это означает, что у нас есть много методов, таких как LOL..

public <T> long saveAccount(T entity)....

public <T> long saveWithAuditLog(T entity, K entity1)....

public <T> long saveWithAuditLogAndEntries(T entity, K entity, M entity)....

ДОПОЛНИТЬ эту ситуацию

Я использую @Transactional в @Controller и просто создаю общий метод сохранения и сохраняю все сущности/модель с помощью этого простого метода сохранения. и если какой-либо метод не сможет успешно сохранить все транзакции в откате контроллера.

Другая ситуация, которая гарантирует, что @Transactional следует использовать с @Controller

В @Controller:

pt.save(entity1);
pt.save(entity2);
int a = 2/0;
pt.save(entity3);

В случае, если @Transactional on Service, первый 2 объекта успешно сохранен, но третий, не откат всей транзакции

В случае, если @Transactional на @Controller имеет все откат транзакции как исключение

почему переполнение стека спрашивается: "Не делайте транзакций в своем контроллере. Поместите их в классы уровня обслуживания"? [источник]

Ответ 1

Вы спрашиваете о лучшей практике, и лучше всего отметить @Transactional в уровне обслуживания, потому что @Controller не должен знать о постоянстве данных в логике MVC.
@Service строится на примере использования, полученном из анализа, и знает о единице работ, а также реализуется мышление с точки зрения повторного использования: если вы переключитесь с веб-контекста на рабочий стол (например, или на какой-либо другой визуальный интерфейс), где @Controller слой не существует, у вас нет проблем, потому что все инкапсулировано в сервисный слой.
A @Service - это контракт, а модификация в слое представления не требует перезаписи кода @Service.
Но Spring не заботятся о том, где вы помещаете свои границы транзакций, вы можете надеть @Controller, но ваше приложение может быть труднее поддерживать.

Надеюсь, это достаточно ясно. Извините, если нет; Английский не мой родной язык.

Ответ 2

так что другие знают, аннотации интерфейса не приветствуются

Spring рекомендует только аннотировать конкретные классы (и методы конкретных классов) с аннотацией @Transactional, а не аннотировать интерфейсы. Вы, конечно, можете поместить аннотацию @Transactional на интерфейс (или метод интерфейса), но это работает только так, как вы ожидали бы, если вы используете прокси на основе интерфейса. Тот факт, что аннотации Java не унаследованы от интерфейсов, означает, что если вы используете прокси-классы на основе класса (proxy-target- class= "true" ) или аспект на основе ткачества (mode = "aspectj" ), то настройки транзакции не распознаются инфраструктурой проксирования и ткачества, и объект не будет обернут в транзакционный прокси, что будет явно плохо.

Ответ 3

Я создал службу верхнего уровня, которая использует другие (не транзакционные) службы. И служба верхнего уровня является транзакционной.

@Service
public class Service1Impl implements Servcie1 {
    public Object method11(){...}
    public Object method12(){...}
}

@Service
public class Service2Impl implements Service2 {
    public method21(){...}
}

public interface Service1 {
    public Object method11();
    public Object method12();
}

public interface Service2 {
    public Object method21();
}

@Transactional
public interface UpperLayerService {}

@Service
public class UpperLayerServiceImpl implements UpperLayerService {
    @Autowired
    private Service2 service2;
    @Autowired
    private Service3 service3;

    public Object doWork() {
        Object o1 = service1.method11();
        Object o2 = service1.method12();
        Object o3 = service2.method21();
        ....
        Object res = null;//...Any code
        return res;
    }
}

Ответ 4

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