Unhappy today-Talking about Spring Transaction

1. Four isolation levels of the database

Dirty read reads uncommitted data.
Non-repeatable read occurs when the same condition is modified. The read value is different. The
phantom read occurs when the same condition is added or deleted. The read quantity is different.

1.1. read_uncommit read uncommitted may occur dirty reads, non-repeatable reads, phantom reads
1.2 read_commit read commits to avoid dirty reads, but non-repeatable reads phantom reads still occur
1.3 repeatable_read reads the same field multiple times are consistent, but phantom reads still occur ( The default isolation level) default
1.4 serializable The highest isolation level

2. Four characteristics of transaction

2.1 The atomic transaction is indivisible
2.2 The data is consistent before and after the consistent execution
2.3 The data is not disturbed by other transactions during the isolated execution
2.4 The data should be persisted to the database after the persistence is executed

3. Seven communication behaviors of affairs

3.1 required If there is no current transaction, create a new transaction, if there is one, add it to the current transaction
3.2 supports Support the current transaction if not, execute it as a non-transaction
3.3 mandatory Use the current transaction if no exception is thrown
3.4 requires_new New transaction hang if there is a transaction
3.5 not_sopported is executed as a non-transactional transaction. If there is a transaction pending,
3.6 never throws an exception
if there is a transaction currently 3.7 nested is executed within a nested transaction if it exists

4. EnableTransactionManagement annotation

4.1 First import the spring-tx jar package

<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.1</version>
</dependency>

4.2 This annotation @Import has TransactionManagementConfigurationSelector, and we also found that the mode of AdviceMode is AdviceMode.PROXY

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({
    
    TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    
    
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

4.3 selectImports method, enter the case Proxy, we find two classes AutoProxyRegistrar and ProxyTransactionManagementConfiguration

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    
    

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
    
    
		switch (adviceMode) {
    
    
			case PROXY:
				return new String[] {
    
    AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
    
    determineTransactionAspectClass()};
			default:
				return null;
		}
	}
}

4.4 First look at the registerBeanDefinitions method of the AutoProxyRegistrar class, and finally register the InfrastructureAdvisorAutoProxyCreator, inheriting AbstractAdvisorAutoProxyCreator, so the main function of this class is to open the role of automatic proxy

if (mode == AdviceMode.PROXY) {
    
    
	AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
	if ((Boolean) proxyTargetClass) {
    
    
		AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		return;
	}
}

4.5 ProxyTransactionManagementConfiguration

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    
    

	// 一个Pointcut 切入点 根据transactionAttributeSource传入attr属性 进行切入
	//Advisor上一篇文章介绍过 Advisor包含了Advice切面逻辑以及Pointcut切入点
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
    
    

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
    
    
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	// 这个Bean 解析@Transaction里面的属性 no public不起作用
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
    
    
		return new AnnotationTransactionAttributeSource();
	}

	// 事务拦截器 保存了@Transaction的属性信息
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
    
    
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
    
    
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

4.6 Various parameters in @Transaction

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    
    
	RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

	Propagation propagation = attributes.getEnum("propagation");
	rbta.setPropagationBehavior(propagation.value());
	Isolation isolation = attributes.getEnum("isolation");
	rbta.setIsolationLevel(isolation.value());

	rbta.setTimeout(attributes.getNumber("timeout").intValue());
	String timeoutString = attributes.getString("timeoutString");
	Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
			"Specify 'timeout' or 'timeoutString', not both");
	rbta.setTimeoutString(timeoutString);

	rbta.setReadOnly(attributes.getBoolean("readOnly"));
	rbta.setQualifier(attributes.getString("value"));
	rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));

	List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
	for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
    
    
		rollbackRules.add(new RollbackRuleAttribute(rbRule));
	}
	for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
    
    
		rollbackRules.add(new RollbackRuleAttribute(rbRule));
	}
	for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
    
    
		rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
	}
	for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
    
    
		rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
	}
	rbta.setRollbackRules(rollbackRules);

	return rbta;
}

5. Give three examples of transaction propagation (REQUIRED, REQUIRES_NEW, NESTED)

5.1 REQUIRED

Class A() {
	// 默认就是REQUIRED
	@Transaction
	public void insertA() {
		.......
	}
	
	@Transaction(propagation = Propagation.REQUIRED)
	public void insertB() {
		.......
	}
}
  1. BEGIN;
  2. insert into a(field1, field2) values(1, 2);
  3. insert into b(field1, field2) values(1, 2);// join the current transaction
  4. COMMIT or ROLLEBACK;

5.2 REQUIRES_NEW

Class A() {
	// 默认就是REQUIRED
	@Transaction
	public void insertA() {
		.......
	}
	
	@Transaction(propagation = Propagation.REQUIRES_NEW)
	public void insertB() {
		.......
	}
}
  1. BEGIN;

  2. insert into a(field1, field2) values(1, 2);

  3. Method A hangs

  4. BEGIN; // Insert logic of B method

  5. insert into b(field1, field2) values(1, 2);

  6. COMMIT OR ROLLEBACK;// The rollback here does not affect the isolation characteristics of insertA logical transactions

  7. Get pending data

  8. COMMIT or ROLLEBACK;

5.3 NESTED

Class A() {
	// 默认就是REQUIRED
	@Transaction
	public void insertA() {
		.......
	}
	
	@Transaction(propagation = Propagation.NESTED)
	public void insertB() {
		.......
	}
}
  1. BEGIN;
  2. insert into a(field1, field2) values(1, 2);
  3. SAVEPOINT xxxx;// Create SAVEPOINT point delete save point RELEASE SAVEPOINT xxxx;
  4. insert into b(field1, field2) values(1, 2);// If this insert is abnormal
  5. ROLLBACK to xxxx; // Then the insert a operation is still not affected
  6. COMMIT;// The transaction is submitted and the insert a operation is normal

NESTED creates one less connection than REQUIRES_NEW

Guess you like

Origin blog.csdn.net/weixin_45657738/article/details/109671006