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



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



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




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

  2. Я также читал в весенних документах, что:



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




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



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

688   4  

4 ответов:

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

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

транзакции в EJB работают аналогично, кстати.

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

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

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

Что касается" внешнего метода", если ваш Боб вызывает один из своих собственных методов, то он не будет делать это через прокси. Помните, что Spring обертывает ваш боб в прокси, ваш Боб не знает об этом. Только звонки "извне" вашего Боба проходят через прокси.

Это поможет?

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

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

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

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

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

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

Comments

    Ничего не найдено.