#java #spring #spring-boot #spring-mvc
#java #spring #spring-boot #spring-mvc
Вопрос:
Я в ужасе. Я нашел сообщения о внедрении @Service
класса в другой @Service
класс. Но что, если оба класса имеют @Transactional
аннотации? @Transactional
имеет значение или, может быть, лучшая практика — внедрять репозитории?
Простой пример:
@Transactional
@Service
public class BBBServiceImpl implements BBBService {
private final BBBRepository bbbRepository;
// @Autowired constructor, methods etc...
}
второй класс:
@Transactional
@Service
public class AAAServiceImpl implements AAAService {
private final AAARepository aaaRepository;
private final BBBService bbbService;
@Autowired
public AAAServiceImpl(AAARepository aaaRepository, BBBService bbbService) {
this.aaaRepository = aaaRepository;
this.bbbService = bbbService;
}
// methods etc...
}
Или лучшее решение:
@Transactional
@Service
public class AAAServiceImpl implements AAAService {
private final AAARepository aaaRepository;
private final BBBRepository bbbRepository;
@Autowired
public AAAServiceImpl(AAARepository aaaRepository, BBBRepository bbbRepository) {
this.aaaRepository = aaaRepository;
this.bbbRepository= bbbRepository;
}
// methods etc...
}
Комментарии:
1. Если бизнес-кейсы требуют, чтобы это
BBBServiceImpl
должно быть@Transactional
, но также требуют чего-то вAAAServiceImpl
, требуется преобразование, например, для инкапсуляции некоторого действия с вызовомBBBService
в транзакции, тогда у вас нет другого выбора. В общем случае транзакция будет возобновлена. Однако вы можете изменить это поведение, установив распространение.
Ответ №1:
В общем, классы не должны быть транзакционными, скорее их методы. Вам следует подать заявку, @Transactional
если соответствующий элемент нуждается в транзакционности. Иногда это означает, что вы будете создавать несколько уровней, потому что вы можете видеть, что даже отдельные части нужны @Transactional
. Иногда это означает, что это необходимо только одному уровню в стеке. Вы должны определить на основе логических требований вашего программного обеспечения.
Случай, когда имеет смысл применить @Transactional
, — это когда у вас есть служба, которая координирует отправку заказов; обновления для отметки отправленного заказа и записи информации о посылке должны происходить транзакционно. Следовательно, OrderHandlingService#shipParcel
должно быть @Transactional
, и так же должны поступать любые методы, связанные с обработкой данных.
Комментарии:
1. Вы правы. Я должен добавить
@Transactional
только для методов, которым это нужно, а не для всего класса.2. Что это за класс, который взаимодействует с репозиторием и при каждом вызове в этом классе отправляется в базу данных?
Ответ №2:
В идеале уровень сервиса (Manager) представляет вашу бизнес-логику и, следовательно, должен быть снабжен аннотациями @Transactional
.
Уровень обслуживания может вызывать разные DAO для выполнения операций с БД. Давайте предположим ситуацию, когда у вас есть 3 операции DAO в методе service. Если ваша первая операция DAO завершилась неудачей, две другие могут быть все еще переданы, и в итоге вы получите несогласованное состояние базы данных. Уровень службы аннотирования может спасти вас от подобных ситуаций.
Также это зависит от Propagation and Isolation
значений.
Даже если вы хотите продолжить ту же транзакцию, но в службе B ее распространение заключается в том, Propagation.REQUIRES_NEW
что она создаст новую транзакцию и выполнит бизнес.
Комментарии:
1. Спасибо за полезную статью. Я думаю, что лучший способ для меня — это откат всего, когда любой метод генерирует исключение. Я генерирую тысячи условий в расписании и проверяю наличие отпусков, конфликтов и праздничных дней, поэтому все должно быть в порядке от A до B, поэтому
REQUIRED
метод по умолчанию должен быть в порядке.
Ответ №3:
Да, вы можете. Поскольку вы можете вызвать другую службу внутри службы, даже если она транзакционная или нет. Нет проблем и рекомендуется