В чем разница между определением @Transactional по методу класса vs
Case1
@Transactional
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
public void method2(){
}
}
Вариант 2
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
@Transactional
public void method2(){
}
}
В случае 1, если возникает какое-либо исключение, он откатывается, но в случае 2 он не работает. Есть ли проблемы с производительностью, если я следую case1?
Ответы
Ответ 1
В случае 1 @Transactional применяется к каждому отдельному методу. В случае 2 @Transactional применяется только к method2(), а не к method1()
Случай 1: - Вызов метода method1() → транзакция запущена. Когда method1() вызывает method2(), новая транзакция не запускается, потому что она уже есть
Случай 2: - Вызов метода method1() → транзакция не запущена. Когда method1() вызывает method2(), NO новая транзакция не запускается. Это связано с тем, что @Transactional не работает при вызове метода из одного и того же класса. Это сработало бы, если бы вы вызывали method2() из другого класса.
Из весеннего справочного руководства:
В режиме прокси (который используется по умолчанию) перехватываются только внешние вызовы методов, поступающие через прокси. Это означает, что самовывоз, по сути, метод в целевом объекте, вызывающий другой метод целевого объекта, не приведет к реальной транзакции во время выполнения, даже если вызванный метод помечен @Transactional. Кроме того, прокси-сервер должен быть полностью инициализирован, чтобы обеспечить ожидаемое поведение, поэтому вам не следует полагаться на эту функцию в коде инициализации, например @PostConstruct.
Ответ 2
@Transactional
для класса применяется к каждому методу в сервисе. Это ярлык. Как правило, вы можете установить @Transactional(readOnly = true)
для класса обслуживания, если вы знаете, что все методы будут обращаться к уровню хранилища. Затем вы можете переопределить поведение с помощью @Transactional
для методов, выполняющих изменения в вашей модели. Проблемы с производительностью между 1) и 2) не известны.
Ответ 3
Цитата из здесь
Рекомендация команды Spring заключается в том, что вы только аннотируете конкретные классы с аннотацией @Transactional, в отличие от аннотирующих интерфейсов.
Поскольку этот механизм основан на прокси-серверах, будут перехвачены только "внешние" вызовы методов, поступающие через прокси-сервер. Это означает, что "самозапуск", т.е. Метод в целевом объекте, вызывающий какой-либо другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод отмечен с помощью @Transactional!
Ответ 4
Предположим, что у вас есть следующий класс:
@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
Аннотация @Transactional
на уровне класса будет применяться ко всем методам класса.
Однако, когда метод аннотируется с помощью @Transactional
(например, updateFoo(Foo foo)
), это будет иметь приоритет над параметрами транзакции, определенными на уровне класса.
Дополнительная информация: