spring-tx之事务管理

前言

事务是大家用的最多的,也是比较关心的一个功能。本章就详细讲解spring-tx模块中事务的实现与spring-boot事务的处理。可能这一节就会把spring-tx说完,事务没有大家想象的那么复杂。

jdbc基本操作

java的连接池,事务管理,持久层(MyBtais,hibernation)都是基于jdbc(Java DataBase Connectivity,java数据库连接)进行演进的。那么仔细看下下面的jdbc代码,从而理解连接池,事务管理,持久层(MyBtais,hibernation)。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Random;

public class Demo {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");//  1. 注册驱动
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","mysql");  // 2. 创建连接
			con.setAutoCommit(false);// 3. 不自动提交,开始事务
		    conn.setReadOnly(true);// 4. 设定只读,或者其他连接设定
			String sql = "insert into t_user(userName,pwd)values(?,?)"; //  需要执行的sql语句
			ps = conn.prepareStatement( sql );// 5. 在不同的statement中设置需要执行的sql语句
			ps.setObject(1, "小高" + i);// 6. 预编译,参数设置
			ps.setObject(2, "123");
			ps.execute(); // 7. 执行语句
			                        // 8. 如果是查询插座,对查询结果进行操作
			con.commit(); // 9. 提交
        } catch (ClassNotFoundException e) {
			 con.rollback(); // 9, 回滚
            e.printStackTrace();
        } catch (SQLException e) {
		    con.rollback(); // 9. 回滚
            e.printStackTrace();
        } finally{
            try {
                if (ps!=null) {
                    ps.close(); // 10. 资源释放
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (conn!=null) {
                    conn.close(); // 10. 资源释放
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
连接池事务管理器持久
1注册驱动
2创建连接
3不自动提交,开始事务
4设定只读,或者其他连接设定
5在不同的statement中设置需要执行的sql语句
6预编译,参数设置
7执行语句
8如果是查询操作,对查询结果进行操作
9提交或者回滚
10资源释放资源释放

// 时序图

spring事务体系

  1. 事务管理器
  2. 事务Interceptor
  3. spring-boot如何启动事务
事务管理器

<! ------------------------- 无情分割线 --------------------------------------------------->

下面声明了TransactionStatus的接口, 实现了TransactionStatus的抽象类AbstractTransactionStatus,还有AbstractTransactionStatus的子类DefaultTransactionStatus与内部类TransactionInfo,其实只需要TransactionInfo一个类就行了,上面几个类的细节不讲述了。

为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。 为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。 为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。

public abstract class AbstractTransactionStatus implements TransactionStatus {
	private boolean rollbackOnly = false;

	private boolean completed = false;

	@Nullable
	private Object savepoint
}
public class DefaultTransactionStatus extends AbstractTransactionStatus {

	@Nullable
	private final Object transaction;

	private final boolean newTransaction;

	private final boolean newSynchronization;

	private final boolean readOnly;

	private final boolean debug;

	@Nullable
	private final Object suspendedResources;
}
	protected final class TransactionInfo {

		@Nullable
		private final PlatformTransactionManager transactionManager;

		@Nullable
		private final TransactionAttribute transactionAttribute;

		private final String joinpointIdentification;

		@Nullable
		private TransactionStatus transactionStatus;

		@Nullable
		private TransactionInfo oldTransactionInfo;
}

<! ------------------------- 无情分割线结束 --------------------------------------------------->

spring事务的核心体系是PlatformTransactionManager以及实现了DataSourceTransactionManager(数据源事务管理器,比如mybatis,spring-jdbc),JpaTransactionManager(Jpa事务管理器),HibernateTransactionManager(hibernate5事务管理器)。本节直接讲解DataSourceTransactionManager,其他的管理器使用场景非常少不做讲解了。

public interface PlatformTransactionManager {

	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

	void commit(TransactionStatus status) throws TransactionException;

	void rollback(TransactionStatus status) throws TransactionException;

}
  1. getTransaction[ 获得事务 ]
  2. commit[ 提交事务 ]
  3. rollback [ 回滚事务 ]

看下这个方法的调用流程,就很容易懂了。一些其他的代码就不要看了,基本是为了jta做了准备

事务Interceptor

TransactionInterceptor 只做了一件事情调用了父类TransactionAspectSupport的invokeWithinTransaction方法,那么大家把注意力放到TransactionAspectSupport的invokeWithinTransaction方法上吧

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

	// PlatformTransactionManager 事务管理
	public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
		setTransactionManager(ptm);
		setTransactionAttributeSource(tas);
	}


	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}
}
	protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {
	    // 得到对象与方法上的Transactio注解
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		// 得到事务管理器,@Transactio注解变量transactionManager,可以指定这个事务由那个事务管理器执行。
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			//开启事务
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
			    // 执行方法
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				// 清理TransactionInfo
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			......
		}
	}
	
	protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
		// 如果 条件成立,返回默认事务管理器
		if (txAttr == null || this.beanFactory == null) {
			return getTransactionManager();
		}
		// 获得 事务管理器的名字
		String qualifier = txAttr.getQualifier();
		// 如果有
		if (StringUtils.hasText(qualifier)) {
		    // 通过事务管理器的名字获得事务管理器,
			return determineQualifiedTransactionManager(qualifier);
		}
		else if (StringUtils.hasText(this.transactionManagerBeanName)) {
			// 默认管理器名字获得管理器
			return determineQualifiedTransactionManager(this.transactionManagerBeanName);
		}
		else {
		     // 获得默认管理器
			PlatformTransactionManager defaultTransactionManager = getTransactionManager();
			if (defaultTransactionManager == null) {
				defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
				this.transactionManagerCache.putIfAbsent(
						DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
			}
			return defaultTransactionManager;
		}
	}
	// 通过事务管理器的名字获得事务管理器
	private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) {
		PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier);
		if (txManager == null) {
			txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
					this.beanFactory, PlatformTransactionManager.class, qualifier);
			this.transactionManagerCache.putIfAbsent(qualifier, txManager);
		}
		return txManager;
	}
spring-boot如何启动事务

spring-boot启动事务很简单只需要EnableTransactionManagement注解或者TransactionManagementConfigurationSelector被ApplicationContext加载,那么就会自动启动事务。详细请看下面的流程

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		// 创建Advisor
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		// 创建 注解识别
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		// 创建方法拦截器与处理器
		advisor.setAdvice(transactionInterceptor());
		advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
}

总结

事务真的很简单,但是为了做很多的兼容于扩展,spring-tx写得很复杂。个人感觉在分布式的微服务框架设计下,很多都不应该要了。

转载于:https://my.oschina.net/u/1261452/blog/3045800

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值