Введение в принцип транзакций Spring и использование синхронизатора транзакций

Spring

Как включить поддержку транзакций

импортировать зависимости

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

После добавления зависимости класс автоматической настройки автоматически настроит объект класса с поддержкой транзакций.

@Configuration
// 引入 spring-boot-starter-jdbc 之后,类路径才存在 PlatformTransactionManager,配置生效
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
		DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public TransactionManagerCustomizers platformTransactionManagerCustomizers(
			ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
		return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
	}

	@Configuration
	@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
	public static class TransactionTemplateConfiguration {

		private final PlatformTransactionManager transactionManager;

		public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
			this.transactionManager = transactionManager;
		}

		@Bean
		@ConditionalOnMissingBean(TransactionOperations.class)
		public TransactionTemplate transactionTemplate() {
			return new TransactionTemplate(this.transactionManager);
		}

	}

	@Configuration
	@ConditionalOnBean(PlatformTransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

        // 启用事务
		@Configuration
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		public static class JdkDynamicAutoProxyConfiguration {

		}

        // 启用事务。没有配置 spring.aop.proxy-target-class 时,默认使用的 proxyTargetClass = true。使用CGLIB来生成代理
		@Configuration
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}

}

загрузка конфигурации

Классы автоматической конфигурации при введении зависимостейTransactionAutoConfigurationэффективный. Его реализация в свою очередь введет следующую конфигурацию

  • AutoProxyRegistrar: класс реализации ImportBeanDefinitionRegistrar, который вызывает свой метод registerBeanDefinitions, когда контейнер начинает вводить более подробную конфигурацию.
    • InfrastructureAdvisorAutoProxyCreator не вступает в силу из-за более низкого приоритета, чем AnnotationAwareAspectJAutoProxyCreator
  • ProxyTransactionManagementConfiguration @Configuration помеченный класс конфигурации
    • BeanFactoryTransactionAttributeSourceAdvisor
      • Внутренний атрибут поинтвута: TransactionAttributeSourcePointcut.
    • AnnotationTransactionAttributeSource считывает значение атрибута @Transactional и предоставляет его в структуру транзакций Spring.
    • TransactionInterceptor
    • TransactionalEventListenerFactory

Как построить прокси-класс с транзакциями

Схема структуры классов BeanFactoryTransactionAttributeSourceAdvisor, AnnotationTransactionAttributeSource и TransactionInterceptor.

Прежде всего, необходимо уяснить несколько понятий:

  • ClassFilter и MethodMatcher совместно реализуют возможность «решать, следует ли перехватывать метод».
  • Pointcut, объединяющий ClassFilter и MethodMatcher, используется для определения необходимости улучшения метода класса.
  • Advice — класс тегов с расширенными возможностями.
  • Advisor, класс, который содержит советы и возможности pointcut в АОП.

Последовательность строительного процесса

Прокси-объект создается с помощью AnnotationAwareAspectJAutoProxyCreator.Принцип заключается в том, что при инициализации контейнера IOC компонент инициализации вызывает метод BeanPostProcessor.postProcessAfterInitialization. То есть в это время выполняется генерация прокси-объекта.

В процессе генерации он будет искать советник в контейнере IOC.После включения управления транзакциями по умолчанию есть BeanFactoryTransactionAttributeSourceAdvisor, а через ProxyFactory будет создан прокси-объект: CglibAopProxy или JdkDynamicAopProxy.Реализация прокси-объекта такова. на основе атрибута spring.aop.proxy-target-class и определяется, является ли проксируемый класс интерфейсом. По умолчанию используется CglibAopProxy.

Врезаться в поток выполнения управления транзакциями

откат транзакции

фиксация транзакции

Классы, связанные с процессами управления транзакциями:

  • TransactionAttribute - DelegatingTransactionAttribute
  • PlatformTransactionManager - DataSourceTransactionManager
  • TransactionStatus
  • TransactionInfo
  • ConnectionHolder

Во всем процессе управления транзакциями функция фиксации и отката в основном реализуется через TransactionInterceptor в зависимости от того, является ли исключение аномальным или нет. DataSourceTransactionManager инкапсулирует фасадный интерфейс двух операций фиксации и отката для вызова TransactionInterceptor Внутри DataSourceTransactionManager он инкапсулирует TransactionStatus, а TransactionObject, содержащийся в TransactionStatus, может получить текущий используемый объект соединения через свой ConnectionHolder, а затем выполнить фиксацию или откат;

Кроме того, Spring также предоставляет TransactionSynchronization в качестве синхронизатора транзакций, который вызывает синхронизатор в момент времени «перед фиксацией, перед откатом, после фиксации, после отката и выполнения отката (или фиксации) завершения».

Использование заключается в следующем

@Transactional(rollbackFor = Exception.class)
@Override
public Author save(Author author) {
    jdbcTemplate.update("insert into author(name) values (?)", author.getName());
	// 注册事务同步器,在事务提交后进行回调
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            System.out.println("after commit...");
        }
    });
    return author;
}