spring事务原理

1 数据库事务

1.1数据库的事物的基本特性
  • A: 原子性(atomicity)
    事物中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事物的失败;
  • C: 一致性(consistency)
    事物结束后系统状态是一致的;
  • I: 隔离性(isolation)
    并发执行的事物彼此无法看到对方的中间状态;
  • D: 持久性(durability)
    事物完成后所做的改动都会被持久化,即使发生灾难性的失败
1.2 数据库的隔离级别
隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phantom Read)
未提交读(Read uncommitted)可能可能可能
已提交读(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串行化(SERIALIZABLE)不可能不可能不可能
  • mysql 中默认级别 Repeatable read。另外要注意的是mysql 执行一条查询语句默认是一个独立的事物,所以看上去效果跟Read committed一样。
  • 可重复读:在同一个事务中重复读取同一条记录的时候,如果在读取的过程中修改过数据,这个时候返回的数据还是没修改过的数据
2 spring事务使用
2.1 编程式事务(API,可以实现部分事务提交)
  • 1、加载SimpleDriverDataSource、2、配置DataSourceTransactionManager,3、配置TransactionTemplate在spring可以可以注入TransactionTemplate实现事务的局部提交
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
            JdbcTemplate jdbcTemplate = new JdbcTemplate(transactionManager.getDataSource());
            transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus status) {

                    DefaultTransactionStatus defaultTransactionStatus = (DefaultTransactionStatus) status;
                    try {
                        jdbcTemplate.update("update user set name='xxx' where id = 1");
                        defaultTransactionStatus.createAndHoldSavepoint();
                        jdbcTemplate.update("update user set name='xxx' where id = 1");
                        int i = 5/0;
                    } catch (Exception e) {

                        throw new RuntimeException(e);
                    }
                    return null;
                }
            });
2.2 声明式事务
  • 通过@Transactional(rollbackFor = Exception.class)来实现的
3 spring事务原理(基于spring-boot)
3.1 @Transactional加载原理
  1. 初始化加载spring-tx包中的ProxyTransactionManagementConfiguration类的时候,由于该类有@Configuration(proxyBeanMethods = false)所以会初始化该类中的所有Bean,里面的方法都有@Bean注解,方法如下:
// 注册通知
@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
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

// 初始化拦截器(最终通过调用该拦截器的invoke方法来实现对spring事务的拦截和处理)
	@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;
	}
  • spring加载的过程中会加载代理对象处理类InfrastructureAdvisorAutoProxyCreator,可以看到包含了BeanPostProcessor的功能和Proxy的功能,
    InfrastructureAdvisorAutoProxyCreator类关系
    • BeanPostProcessor创建了原始对象之后会对原始对象进行进一步的处理
    • Proxy的功能会扫描原始对象中的方法是否存在@Transactional注解确定是否需要生成代理对象,扫描的调用方法在SpringTransactionAnnotationParser的方法parseTransactionAnnotation
@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}
3.2 生成代理对象
  • jdk代理
    • 针对有接口且proxyTargetClass=false(默认是false)的配置生成jdk代理,一般默认情况都是生成jdk代理对象
  • cglib代理
    • 如果配置了proxyTargeClass=true的时候,生成cglib代理
3.3 事务执行
  • 由于配置了拦截器TransactionInterceptor,在执行事务的方法时候会调用拦截中的invoke方法
public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		//调用父类TransactionAspectSupport的方法
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
  • 事务的实现要包含了三个对象
    • PlatformTransactionManager事务管理器,
    • TransactionAttribute 可以看到事务属性中配置的正式事务的一些配置在这里插入图片描述
  • DefaultTransactionStatus 事务运行过程中的状态,设置回滚点、获取事务信息的
    DefaultTransactionStatus
  • 正在的代理逻辑在TransactionAspectSupport中,实现的过程如下:
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		TransactionAttributeSource tas = getTransactionAttributeSource();
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		final TransactionManager tm = determineTransactionManager(txAttr);

		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			//(可以忽略)ReactiveTransactionManager事务管理器
		}
		//spring的事务管理器
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}

			if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			//调用其他类型的事务管理器
	}
4 spring事务不生效问题
  • 方法内部一个不加事务的方法调用另外一个加了事务的方法,因为事务要生效需要通过代理调用来实现,方法内部直接调用的时候没有经过代理所以事务不会生效,可以通过下面的方式来处理
<aop:aspectj-autoproxy expose-proxy="true"/>
//获取对象
(XXX) AopContext.currentProxy()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值