Транзакция 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 к методу, который должен открыть транзакцию.Здесь следует отметить, что когда тег
<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>
В это время вступит в силу первый
Давайте приступим к анализу соответствующего исходного кода Spring. Во-первых, давайте взглянем на анализ тега
(Щелкните правой кнопкой мыши, чтобы увеличить изображение)
Этот метод относительно длинный, ключевые части помечены, а самое внешнее решение if ограничивает анализ тега
Помните, что когда в теге
Основное назначение этих двух методов — регистрация 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 (текст / Чжан Цян)