Метод @Transactional вызывает другой метод без аннотации @Transactional?


89

Я видел метод в классе Service, который был помечен как @Transactional, но он также вызывал некоторые другие методы в том же классе, которые не были отмечены как @Transactional.

Означает ли это, что вызов отдельных методов заставляет приложение открывать отдельные соединения с БД или приостанавливать родительскую транзакцию и т. Д.?

Каково поведение по умолчанию для метода без аннотаций, который вызывается другим методом с @Transactionalаннотацией?

Ответы:


117

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

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

Более подробную информацию можно найти в разделе « Декларативное управление транзакциями» документации по весенним транзакциям .

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


это весеннее поведение по умолчанию?
goe

Да. Это поведение по умолчанию.
Arun P Johny

2
@Tomasz Да. Но следует также отметить, что изменение распространения транзакции в методе, который вызывается из другого метода @Transactional, не повлияет.
Fil

1
@Tomasz, я это имел в виду, говоря will follow the transaction definitions given in the called method. Но если вызов исходит от того же экземпляра объекта, он не будет иметь никакого эффекта, поскольку вызов не будет распространяться через прокси-серверы aop, которые отвечают за обслуживание транзакции.
Arun P Johny

5
@Filip, это не совсем правильно. Если вы вызываете метод с @Transactionalопределением из другого объекта / экземпляра, тогда, даже если вызывающий метод имеет другие @Transactionalатрибуты, вызываемый метод будет следовать своему собственному определению транзакции.
Arun P Johny

23
  • Означает ли это, что вызов отдельных методов заставляет приложение открывать отдельные подключения к БД или приостанавливать родительскую транзакцию и т. Д.?

Это зависит от уровня распространения . Вот все возможные значения уровней .

Например, если уровень распространения - ВСТАВЛЕННЫЙ, текущая транзакция будет «приостановлена» и будет создана новая транзакция ( примечание: фактическое создание вложенной транзакции будет работать только для определенных менеджеров транзакций )

  • Каково поведение по умолчанию для метода без каких-либо аннотаций, который вызывается другим методом с аннотацией @Transactional?

Уровень распространения по умолчанию (то, что вы называете «поведением») ТРЕБУЕТСЯ . В случае вызова «внутреннего» метода, который имеет @Transactionalаннотацию (или транзакция декларативно выполняется через XML), он будет выполняться в рамках той же транзакции , например, «ничего нового» не создается.


А как насчет дополнительных вызовов NOT_SUPPORTED, которые не имеют аннотации? Наследует ли он NOT_Supported или они открыли новую транзакцию, поскольку REQURED является значением по умолчанию? Например: f1.call () {f2 ()} с аннотацией NOT_SUPPORTED для f1 и non для f2.
Дэйв

8

@Transactional отмечает границу транзакции (начало / конец), но сама транзакция привязана к потоку. После запуска транзакция распространяется по вызовам методов до тех пор, пока исходный метод не вернется, а транзакция не зафиксируется / не откатится.

Если вызывается другой метод с аннотацией @Transactional, то распространение зависит от атрибута распространения этой аннотации.


Эти 3 ответа в некоторой степени противоречат друг другу, не знаю, какой из них более точен.
Эрик Ван

1
@EricWang Просто хотел поделиться, что сегодня я протестировал этот сценарий, и ответ Аруна П. Джонни (с комментариями) является наиболее точным для этого сценария внутренних вызовов.
Vinay Vissh

3

Внутренний метод повлияет на внешний метод, если внутренний метод не аннотирован @Transactional.

Если внутренний метод также аннотирован @Transactional с REQUIRES_NEW, произойдет следующее.

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

Внутренний метод аннотируется REQUIRES_NEWи выдает исключение RuntimeException, поэтому он установит для своей транзакции откат, но НЕ ВЛИЯЕТ на внешнюю транзакцию. Внешняя транзакция приостанавливается, когда начинается внутренняя транзакция, и затем ВОЗОБНОВЛЯЕТСЯ ПОСЛЕ завершения внутренней транзакции. Они работают независимо друг от друга, поэтому внешняя транзакция МОЖЕТ успешно зафиксироваться.


1
Чтобы прояснить для новичков, я почти уверен, что innerMethod () должен быть на другом bean-компоненте (он же Java-объект, управляемый Spring), чем outerMethod (). Если они оба находятся в одном и том же компоненте, я не думаю, что innerMethod действительно будет использовать поведение Transactional, объявленное в его аннотации. Скорее он будет использовать то, что объявлено в объявлении outerMethod (). Это связано с тем, как Spring обрабатывает AOP, который используется для аннотаций @Transactional ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/… )
johnsimer
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.