Spring – @Transactional – Что происходит в фоновом режиме?

Я хочу знать, что на самом деле происходит, когда вы комментируете метод с помощью @Transactional ? Конечно, я знаю, что Spring проведет этот метод в транзакции.

Но у меня есть следующие сомнения:

  1. Я слышал, что Spring создает прокси-class ? Может кто-то объяснить это более подробно . Что на самом деле находится в этом прокси-classе? Что происходит с фактическим classом? И как я могу увидеть созданный прокси-class Spring
  2. Я также читал в весенних документах, что:

Примечание. Поскольку этот механизм основан на прокси-серверах, будут перехвачены только «внешние» вызовы методов, поступающие через прокси-сервер . Это означает, что «self-invocation», то есть метод внутри целевого объекта, вызывающий какой-либо другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызываемый метод отмечен @Transactional !

Источник: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Почему только вызовы внешних методов будут в транзакции, а не в методах самозапуска?

4 Solutions collect form web for “Spring – @Transactional – Что происходит в фоновом режиме?”

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

Но на очень высоком уровне Spring создает прокси для classов, которые объявляют @Transactional на самом classе или на членах. Прокси-сервер в большинстве случаев невидим во время выполнения. Это дает возможность Spring вводить поведение до, после или вокруг вызовов методов в прокси-объект. Управление транзакциями – это всего лишь один пример поведения, к которому можно подключиться. Проверки безопасности – это еще один. И вы можете предоставить свои собственные тоже для таких вещей, как ведение журнала. Поэтому, когда вы комментируете метод с @Transactional , Spring динамически создает прокси-сервер, который реализует один и тот же интерфейс (-и) как class, который вы комментируете. И когда клиенты совершают вызовы в ваш объект, вызовы перехватываются, а поведение вводится через механизм прокси.

Между прочим, транзакции в EJB тоже работают.

Как вы заметили, механизм прокси работает только тогда, когда вызовы поступают от какого-то внешнего объекта. Когда вы делаете внутренний вызов внутри объекта, вы действительно делаете вызов через « эту » ссылку, которая обходит прокси. Однако есть способы обойти эту проблему. Я объясняю один подход на этом форуме, в котором я использую BeanFactoryPostProcessor для ввода экземпляра прокси-сервера в classы саморегуляции во время выполнения. Я сохраняю эту ссылку в переменной-члене, называемой « я ». Затем, если мне нужно сделать внутренние вызовы, требующие изменения статуса транзакции streamа, я направляю вызов через прокси (например, « me.someMethod () ».) Сообщение на форуме объясняется более подробно. Обратите внимание, что теперь код BeanFactoryPostProcessor будет немного другим, так как он был записан в Spring 1.rame. Но, надеюсь, это дает вам представление. У меня есть обновленная версия, которую я мог бы сделать доступной.

Когда Spring загружает ваши определения bean-компонентов и настроен на поиск аннотаций @Transactional, он создаст эти прокси-объекты вокруг вашего фактического компонента. Эти прокси-объекты являются экземплярами classов, которые автоматически генерируются во время выполнения. Поведение этих объектов-прокси по умолчанию при вызове метода заключается в том, чтобы вызвать тот же метод для «целевого» компонента (т. Е. Вашего компонента).

Тем не менее, прокси могут также поставляться с перехватчиками, и когда они присутствуют, эти перехватчики будут вызываться прокси-сервером, прежде чем он вызовет метод вашего целевого компонента. Для целевых компонентов, аннотированных с помощью @Transactional, Spring создаст TransactionInterceptor и передаст его созданному прокси-объекту. Поэтому, когда вы вызываете метод из клиентского кода, вы вызываете метод в прокси-объекте, который сначала вызывает TransactionInterceptor (который начинает транзакцию), что в свою очередь вызывает метод на вашем целевом компоненте. Когда вызов завершается, TransactionInterceptor совершает / откатывает транзакцию. Он прозрачен для кода клиента.

Что касается объекта «внешнего метода», если ваш компонент ссылается на один из его собственных методов, то он не будет делать этого через прокси. Помните, что Spring обертывает ваш bean-компонент в прокси-сервер, ваш bean-компонент не знает об этом. Только прокси-серверы «снаружи» вашего компонента проходят через прокси-сервер.

Это помогает?

Как визуальный человек, мне нравится взвесить диаграмму последовательности прокси-шаблона. Если вы не знаете, как читать стрелки, я читаю первый такой: Client выполняет Proxy.method() .

  1. Клиент вызывает метод на целевой стороне с его точки зрения и молча перехватывает прокси-сервер
  2. Если задан аспект, прокси-сервер выполнит его
  3. Затем выполняется фактический метод (цель)
  4. Последующие и последующие метаданные являются необязательными аспектами, которые выполняются после возвращения метода и / или если метод генерирует исключение
  5. После этого прокси выполняет следующий аспект (если он определен)
  6. Наконец, прокси возвращается к вызывающему клиенту

Схема последовательности прокси-шаблонов (Мне разрешили опубликовать фотографию при условии, что я упомянул ее истоки. Автор: Ноэль Вайс, сайт: http://www.noelvaes.eu)

Самый простой ответ: какой бы метод вы не объявляли @Transactional, граница начала транзакции и граница заканчивается, когда метод завершается.

Если вы используете вызов JPA, то все транзакции находятся на этой границе транзакции. Допустим, вы сохраняете объекты entity1, entity2 и entity3. Теперь, сохраняя сущность3, возникает исключение, так как enitiy1 и entity2 входят в одну транзакцию, поэтому entity1 и entity2 будут откат с сущностью3.

Транзакция: (entity1.save, entity2.save, entity3.save). Любое исключение приведет к откату всех транзакций JPA с БД. Внутренняя транзакция JPA используется весной.

Давайте будем гением компьютера.