Транзакции анализа исходного кода Spring

задняя часть база данных Spring API

Транзакция Spring — это технология, которая часто используется в нашей повседневной работе. Spring предоставляет нам аспекты программирования, аннотации и АОП для использования транзакции Spring. можно выбрать в зависимости от требований.В качестве примера мы возьмем метод аннотации для анализа принципа и реализации исходного кода транзакций Spring.

Во-первых, давайте кратко рассмотрим, как используются и настраиваются транзакции Spring:

<tx:annotation-driven transaction-manager="transactionManager"/>
 <bean id="transactionManager" 
         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
 </bean>

Добавьте аннотацию @Transactional к методу, который должен открыть транзакцию.Здесь следует отметить, что когда тег не указывает атрибут transaction-manager, он будет искать фиксированный идентификатор с именем transactionManager по умолчанию.Бин выступает в роли менеджера транзакций.Если нет бина с id transactionManager и не указано значение (менеджер транзакций) при использовании аннотации @Transactional, программа сообщит об ошибке. Когда мы настраиваем более двух тегов , следующим образом:

<tx:annotation-driven transaction-manager="transactionManager1"/>
<bean id="transactionManager1" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource1"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager2"/>
<bean id="transactionManager2" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource2"/>
</bean>

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

Давайте приступим к анализу соответствующего исходного кода Spring. Во-первых, давайте взглянем на анализ тега . Здесь читатели должны иметь определенное представление о процессе анализа пользовательских тегов Spring. Автор также опубликует соответствующие статьи в будущем. Заблокируйте TxNamespaceHandler:

(Щелкните правой кнопкой мыши, чтобы увеличить изображение)

Этот метод относительно длинный, ключевые части помечены, а самое внешнее решение if ограничивает анализ тега только один раз, поэтому только первый проанализированный тег будет иметь силу. Часть синего прямоугольника регистрирует три BeanDefinition, а именно AnnotationTransactionAttributeSource, TransactionInterceptor и BeanFactoryTransactionAttributeSourceAdvisor, и добавляет первые два BeanDefinition к атрибутам третьего BeanDefinition Эти три компонента поддерживают всю функцию транзакции, которая будет подробно описана позже. Давайте сначала посмотрим на первый метод красного ящика:

Помните, что когда в теге не указан атрибут transaction-manager, он будет искать bean-компонент с фиксированным идентификатором с именем transactionManager в качестве менеджера транзакций по умолчанию, что реализовано здесь. Давайте посмотрим на второй метод красного ящика:

Основное назначение этих двух методов — регистрация InfrastructureAdvisorAutoProxyCreator. Какова цель регистрации этого класса? Давайте посмотрим на иерархию этого класса:

Мы обнаружили, что этот класс косвенно реализует интерфейс BeanPostProcessor. Мы знаем, что Spring гарантирует, что все bean-компоненты будут вызывать свой метод postProcessAfterInitialization при их создании. Мы можем использовать этот метод для переноса и изменения bean-компонентов, и реальная реализация этого метода находится в его родительский класс AbstractAutoProxyCreator В классе:

Я думаю, что все видели цель вышеописанного метода: сначала узнать beanName всех классов, соответствующих Advisor, а затем получить эти bean-компоненты и вернуть их через метод beanFactory.getBean. Не знаю, помните ли вы еще три класса, упомянутые в начале статьи, среди них BeanFactoryTransactionAttributeSourceAdvisor реализует интерфейс Advisor, поэтому этот бин будет извлекаться здесь, а два других бина вплетены в BeanFactoryTransactionAttributeSourceAdvisor, так что это Также будут извлечены вместе, на следующем рисунке показана иерархия класса BeanFactoryTransactionAttributeSourceAdvisor:

Давайте посмотрим, как Spring получает соответствующий бустер среди всех бустеров-кандидатов:

Концепция вводного усовершенствования упоминается в приведенном выше методе. Вот краткое описание. Вводное усовершенствование — это особый тип усовершенствования. Он не вплетает усовершенствования в целевой метод, а создает новые методы и свойства для целевого класса. точки соединения для внесения улучшений находятся на уровне класса, а не на уровне метода. Посредством усовершенствования введения мы можем добавить реализацию интерфейса в целевой класс, то есть исходный целевой класс не реализует интерфейс.Посредством усовершенствования введения мы можем создать прокси, реализующий интерфейс для целевого класса.Для метода использования , пожалуйста, обратитесь к справочной ссылке в конце статьи. Кроме того, этот метод использует два перегруженных метода canApply для поиска соответствующего энхансера для целевого класса, где первый метод canApply вызывает второй метод canApply и передает false в качестве третьего параметра:

В приведенной выше иерархии класса BeanFactoryTransactionAttributeSourceAdvisor мы видим, что он реализует интерфейс PointcutAdvisor, поэтому для оценки будет вызываться метод canApply в красном поле. :

Здесь transactionAttributeSource — это AnnotationTransactionAttributeSource в двух bean-компонентах, вплетенных в BeanFactoryTransactionAttributeSourceAdvisor, которые мы видели в начале статьи.Мы продолжаем отслеживать метод canApply с TransactionAttributeSourcePointcut в качестве первого параметра:

Мы отслеживаем метод pc.getMethodMatcher(), то есть метод getMethodMatcher класса TransactionAttributeSourcePointcut реализован в его родительском классе:

Метод обнаружения возвращает это напрямую, то есть следующий метод methodMatcher.matches является методом совпадений, который вызывает TransactionAttributeSourcePointcut:

Выше мы видели, что этот tas на самом деле AnnotationTransactionAttributeSource, Цель здесь состоит в том, чтобы определить, есть ли аннотация @Transactional в нашем бизнес-методе или классе, и отследить метод getTransactionAttribute AnnotationTransactionAttributeSource:

Объявление транзакции в методе имеет наивысший приоритет, и если в методе нет объявления, оно ищется в классе:

this.annotationParsers инициализируется при инициализации класса AnnotationTransactionAttributeSource:

Таким образом, annotationParser.parseTransactionAnnotation должен вызвать метод SpringTransactionAnnotationParser parseTransactionAnnotation:

На этом этапе мы наконец-то увидели аннотацию Transactional, которая, несомненно, является атрибутом, объявленным в аннотации синтаксического анализа:

В этом методе мы видим анализ различных общих или необычных атрибутов, объявленных в аннотации Transactional, На этом инициализация транзакции завершается и начинается фаза реального выполнения.

В методе wrapIfNecessary класса AbstractAutoProxyCreator выше, после получения энхансера, соответствующего целевому бину, для бина будет создан прокси.Эта часть контента будет подробно описана в статье Spring AOP.Вот краткое описание для ваше понимание.Когда целевой метод прокси-класса будет выполнен, будет вызван метод getAdvice советника для получения MethodInterceptor и будет выполнен его метод вызова, а метод getAdvice класса BeanFactoryTransactionAttributeSourceAdvisor, главный герой этой статьи, вернет в него вплетен еще один bean-компонент, который мы видели в начале статьи, это TransactionInterceptor, который реализует MethodInterceptor, поэтому мы анализируем его метод вызова:

Этот метод очень длинный, но общая логика все еще очень ясна.Предпочтительнее получать атрибуты транзакции.Возвращаемое значение метода getTransactionAttrubuteSource() здесь также является AnnotationTransactionAttributeSource, вплетенным в TransactionInterceptor, который мы видели в начале статьи. Атрибуты транзакций были проанализированы и сохранены в кеше, поэтому они будут получены непосредственно из кеша, а затем получен сконфигурированный TransactionManager, который является методом defineTransactionManager.Если в конфигурации не указан менеджер транзакций и есть нет bean-компонента с идентификатором по умолчанию с именем transactionManager, будет сообщено об ошибке, а затем для различной обработки декларативных транзакций и программных транзакций создается информация о транзакции, выполняется целевой метод и, наконец, выполняется операция отката или фиксации в соответствии с результат выполнения.Сначала анализируем процесс создания транзакции. Перед анализом я надеюсь, что вы сможете сначала понять поведение распространения транзакций Spring, что поможет вам понять следующий исходный код.Вот краткое введение.Для получения более подробной информации, пожалуйста, обратитесь к официальной документации Spring самостоятельно, которая содержит обновленные и подробные введения.

Поведение Spring при распространении транзакций определяется в классе перечисления Propagation Всего существует семь типов, а именно:

ТРЕБУЕТСЯ: бизнес-метод должен работать в контейнере. Если метод запущен, он уже находится в транзакции, затем присоединитесь к транзакции, в противном случае создайте новую транзакцию самостоятельно, что является поведением распространения транзакции по умолчанию.

NOT_SUPPORTED: объявленный метод не требует транзакции. Если метод не связан с транзакцией, контейнер не откроет для него транзакцию.Если метод вызывается в транзакции, транзакция будет приостановлена.После завершения вызова исходная транзакция возобновит выполнение.

ТРЕБУЕТСОБОЙ: независимо от того, есть ли транзакция, этот метод инициирует новую транзакцию для себя. Если метод уже запущен в транзакции, исходная транзакция приостанавливается и создается новая транзакция.

ОБЯЗАТЕЛЬНО: этот метод может выполняться только в существующей транзакции, а бизнес-методы не могут инициировать свои собственные транзакции. При вызове без транзакции контейнер выдает исключение.

ПОДДЕРЖКА: метод вызывается в рамках транзакции и становится частью транзакции. Если метод вызывается вне области транзакции, метод выполняется без транзакции.

НИКОГДА: метод никогда не должен выполняться в рамках транзакции. Если это так, сгенерируйте исключение. Только метод не связан ни с какой транзакцией, он будет выполняться нормально.

NESTED: если активная транзакция существует, запустите вложенную транзакцию. Если активной транзакции нет, она выполняется по атрибуту REQUIRED. Он использует одну транзакцию с несколькими точками сохранения, которые можно откатить. Откат внутренней транзакции не влияет на внешнюю транзакцию. Он работает только с диспетчером транзакций DataSourceTransactionManager.

Чтобы определить, есть ли транзакция в текущем потоке, нужно определить, является ли записанное соединение с базой данных пустым, а состояние transactionActive — истинным.

REQUIRESNEW откроет новую транзакцию и приостановит исходную транзакцию. Конечно, для открытия новой транзакции требуется новое подключение к базе данных:

Основная цель операции приостановки состоит в том, чтобы установить для текущего соединения ConnectionHolder значение null, сохранить исходную информацию о транзакции, чтобы упростить последующее восстановление исходной транзакции, и сбросить текущую информацию о транзакции. Давайте посмотрим, как Spring запускает новую транзакцию:

Здесь мы видим получение соединения с базой данных.Если новой транзакции необходимо получить новое соединение с базой данных и установить для него уровень изоляции, доступ только для чтения и другие атрибуты, следует записать информацию о транзакции в текущий поток:

Следующим шагом является запись статуса транзакции и возврат информации о транзакции:

Затем это выполнение нашего целевого бизнес-метода.В соответствии с различными результатами выполнения выполняется операция фиксации или отката.Давайте сначала рассмотрим операцию отката:

Условие отката по умолчанию равно RuntimeException или Error, и мы также можем настроить его самостоятельно.

Точки сохранения обычно используются для встроенных транзакций, и откат встроенных транзакций не приведет к откату внешних транзакций. Посмотрим на откат новой транзакции:

Очень просто получить соединение с базой данных текущего потока и вызвать его метод отката для отката, используя API, предоставляемый базовым соединением с базой данных. Наконец, есть операция по очистке и возобновлению ожидающих транзакций:

Если транзакция приостановлена ​​до выполнения транзакции, приостановленную транзакцию необходимо возобновить после выполнения текущей транзакции.Когда транзакция приостановлена, исходная информация о транзакции сохраняется, а текущая информация о транзакции сбрасывается.Поэтому восстановление Операция заключается в установке текущей информации о транзакции.Это исходная информация о транзакции, сохраненная ранее. На этом операция отката транзакции завершена.Давайте посмотрим на операцию фиксации транзакции:

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

Операция фиксации также очень проста для вызова метода фиксации базового API соединения с базой данных.


Ссылка на ссылку:

http://blog.163.com/asd_wll/blog/static/2103104020124801348674/

https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#spring-data-tier


Данная статья защищена оригиналом, перепечатка без разрешения автора запрещена. linkedkeeper.com (текст / Чжан Цян)