今天不爽-浅谈Spring Transaction

本文详细介绍了数据库的四种隔离级别(读未提交、读已提交、可重复读、序列化)及其影响,事务的四个特性(原子性、一致性、隔离性、持久性)以及事务传播行为。此外,还解读了Spring的@TransactionManagement注解和TransactionManagementConfiguration的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 数据库的四个隔离级别

脏读 读取了未提交的数据
不可重复读 发生在修改 同样的条件 读取的值是不一样的
幻读 发生在新增删除 同样的条件 读取出来的数量是不一样的

1.1. read_uncommit 读未提交 可能发生脏读 不可重复读 幻读
1.2 read_commit 读提交 避免脏读 但还是会发生不可重复读 幻读
1.3 repeatable_read 对同一字段多次去读是一致的 但还是会发生幻读 (默认的隔离级别)default
1.4 serializable 最高的隔离级别

2. 事务四个特性

2.1 原子性 事务不可分割
2.2 一致性 执行前后数据一致
2.3 隔离性 执行期间不被其他事务干扰
2.4 持久性 执行完毕后 数据应被持久话到数据库

3. 事务的七个传播行为

3.1 required 如果当前没有事务就新建一个事务 如果有则加入到当前事务
3.2 supports 支持当前事务 如果没有 就以非事务执行
3.3 mandatory 使用当前事务 如果没有抛出异常
3.4 requires_new 新建事务 如果存在事务 则挂起
3.5 not_sopported 以非事务执行 如果存在事务 挂起
3.6 never 如果当前存在事务 抛异常
3.7 nested 如果存在 则在嵌套事务内执行 没有则新建

4. EnableTransactionManagement注解

4.1 首先导入spring-tx jar包

<!-- 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 这个注解 @Import了TransactionManagementConfigurationSelector,我们也发现了AdviceMode的mode为 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方法,进到case Proxy下,我们发现两个类AutoProxyRegistrar和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 先看AutoProxyRegistrar这个类的registerBeanDefinitions方法,最终注册了InfrastructureAdvisorAutoProxyCreator,继承了AbstractAdvisorAutoProxyCreator,所以这个类的主要作用就是开启自动代理的作用

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 @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. 举三个例子 事务传播(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);// 加入到当前事务
  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. A方法挂起

  4. BEGIN;// B方法的插入逻辑

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

  6. COMMIT OR ROLLEBACK;// 这里的rollback 不影响insertA逻辑 事务的隔离特性

  7. 拿到挂起的数据

  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;// 创建SAVEPOINT点 删除保存点 RELEASE SAVEPOINT xxxx;
  4. insert into b(field1, field2) values(1, 2);// 如果这个插入异常
  5. ROLLBACK to xxxx; // 那么insert a操作仍不受影响
  6. COMMIT;// 事务提交 insert a操作正常

NESTED相比于REQUIRES_NEW 少创建一次连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值