Spring инжиниринг нескольких источников данных и нескольких менеджеров транзакций приводит к сбою транзакции

Spring

1. Предпосылки

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

2. Анализ причин

Сначала не говорите много о коде, о том, почему вы кодируете, знаете ли,comНа обратной стороне обычно находится название компании.

на фото выше1Это последнее, последнее на первом месте,pxhTransactionManagerэто не проблема, потому что красивое имяtransactionManagerОн у нас уже занят (первый релиз хорош разве что для исследования ямы), проблема должна лежать и определять его заново<tx:annotation-driven>Этикетка.

Тут очень странно, вообще все в проекте напрямую<tx:annotation-driven/>Просто объявите эту аннотацию, зачем вы хотите ее написать?transaction-managerАтрибуты, тут мы предполагаем (на самом деле это так), что это дефолтный менеджер указанной транзакции.Так как он дефолтный, то есть дефолтное имя.Да как все думают, дефолтное имяtransactionManager,фактическиIDEAЭто уже дало нам подсказку, как показано ниже

Бесполезное объявление свойств по умолчанию, и мышка на немAlt+EnterПервую подсказку можно удалить

определить несколько разtxТеги — это странные вещи, которые можно делать в одноэлементном мире.Spring, и мы можем предположить, основываясь на результатах и ​​коде,<tx:annotation-driven>Этикетка берет на себя先入为主Стратегия, которая приводит к тому, что диспетчер транзакций, который мы вызываем по умолчанию, становитсяpxhTransactionManager, однако это не тот источник данных, который должен вызывать наш код, поэтому откат недопустим.

3. Анализ кода

Угадывание должно основываться на коде, так как теги определены вXMLфайл, то мы начинаем сSpringРазбор нашего файла конфигурации начинает выглядеть так, как будто мы начинаем сSpringсуществуетWeb.xmlОкно запуска, определенное в файле, запускается, как всем известноContextLoaderListener

ListenerобаServletContextListenerКласс реализации запускается при запуске контейнера.contextInitializedметод, введитеcontextLoader.initWebApplicationContextметод

Этот метод в основном является контейнер инициализации контекста, бетонbeanЗагрузка и другие методы находятся вconfigureAndRefreshWebApplicationContext()метод

Войтиwac.refresh()метод, здесьwacда классXmlWebApplicationContext, я не буду говорить о вышесказанном, это слишком раздражает и я не понимаю...

XmlWebApplicationContextНаследование этого класса очень сложно, вотrefresh()Фактический код находится вAbstractApplicationContextв классе

Сразу к темеobtainFreshBeanFactory()метод

loadBeanDefinitions(beanFactory)Разбор методаXMLфайл, введитеAbstractXmlApplicationContextв классеloadBeanDefinitions()метод

ВойтиXmlWebApplicationContext.loadBeanDefinitions()метод

ВойтиAbstractBeanDefinitionReader.loadBeanDefinitions()ряд перегруженных методов, а затем введитеAbstractBeanDefinitionReaderКатегорияloadBeanDefinitions(String location, Set<Resource> actualResources)метод

ВойтиXmlBeanDefinitionReaderКатегорияloadBeanDefinitions(EncodedResource encodedResource)метод

проходить черезXmlBeanDefinitionReaderКатегорияdoLoadBeanDefinitions()способ входаregisterBeanDefinitions()метод,

ВойтиDefaultBeanDefinitionDocumentReaderКатегорияregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)метод

затем введитеparseBeanDefinitions()метод

картинаtx:Такие теги относятся к пользовательскому тегу goBeanDefinitionParserDelegate.parseCustomElement()метод

Смысл в том, чтобы через пространство имен найти соответствующий класс обработки, ввестиDefaultNamespaceHandlerResolverКатегорияresolve()метод

нижеhandlerMappingsСоответствие между пространствами имен и классами обработки

ВойтиTxNamespaceHandlerclass видно, что несколько ключевых классов инициализированы

Вернитесь ко входу прямо сейчас, войдитеNamespaceHandlerSupport.parse()метод

Видно, что необходимо реализоватьAnnotationDrivenBeanDefinitionParser.parse()метод

Можно обнаружить, что появились уже знакомые нам пакеты, здесь мы догадываемся, что это тоже своего рода фабричный паттерн, а по сути — это классы обработки различных тегов, которые необходимо ввести в пространство имен. Что нам нужно, чтобы войти, этоspring-txпакет, вAnnotationDrivenBeanDefinitionParserвнутренний статический классAopAutoProxyConfigurerстатический методconfigureAutoProxyCreatorявляется ключом, здесь также объясняется, почему предубеждения,

только если нет такого типаbeanбудет правильно, когдаbeanинициализируется и регистрируется в контейнере, иxmlСинтаксический анализ осуществляется сверху вниз, поэтому менеджер транзакций, который мы разместили ниже, не работает должным образом, а безжалостно отбрасывается.

Также в этой части кода объясняетсяtransaction-managerПроцесс разбора атрибута тега, здесь также задается значение по умолчанию

существуетTransactionInterceptorКатегорияinvoke()Метод является конкретным исполнителем прокси-объекта транзакции, а конкретный код находится вTransactionAspectSupport.invokeWithinTransaction()Добрый,

на фото вышеcompleteTransactionAfterThrowingметод, который определяет, что нужно откатить при возникновении исключения, если@TransactionalАннотация не указанаrollbackForсвойства, введитеDefaultTransactionAttribute, так только вRuntimeExceptionвведите исключение иErrorоткат

4. Решения

На самом деле решения есть онлайн, т.е.@TransactionalСоответствующий менеджер транзакций указывается в аннотации, например@Transactional("pxhTransactionManager") @Transactional("transactionManager")

См. код ниже для конкретной причины.TransactionAspectSupportв классе