Spring注解实现事物管理以及源码解析

Spring基于注解管理事物需要两个注解:

  1.  @EnableTransactionManagement 开启基于注解事务管理功能; 
  2. @Transactional 表示当前方法是一个事务方法;

@EnableTransactionManagement用于配置类,用于开启Spring基于注解管理事物的功能。@Transactional注解用于方法上,表示当前方法是一个事物方法。

@EnableTransactionManagement开启基于注解管理事物:

@EnableTransactionManagement
@ComponentScan("cn.zsm.transaction")
@Configuration
public class TxConfig {
	
	//数据源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("123456");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		return dataSource;
	}
	
	//JdbcTemplate 模板类,用于简化增删改查操作
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//注册事务管理器在容器中
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	

}

一个简单的数据库链接配置和Spring的事物管理器配置完成。可以看到配置类中上有三个注解:@configuration、@Component、@EnableTransactionManagement,分别用于标识当前类为配置类、扫描指定路径下的包、开启Spring基于注解管理事物功能。下面来看一下@EnableTransactionManagement注解都做了什么:

@EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class) //导入组件
public @interface EnableTransactionManagement {

	//true创建基于子类(CGLIB)的代理,false创建基于Java接口的代理
	boolean proxyTargetClass() default false;

	// 指示应如何应用事务通知。默认{@link AdviceMode#PROXY}. 
	AdviceMode mode() default AdviceMode.PROXY;

	//在特定连接点应用多个通知时,指示事务顾问的执行顺序。默认Ordered#LOWEST_PRECEDENCE
	int order() default Ordered.LOWEST_PRECEDENCE;

}

@EnableTransactionManagement给容器中导入了TransactionManagementConfigurationSelector实例,

TransactionManagementConfigurationSelector:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	//根据adviceMode类型,选择给容器导入的组件
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY: 
				return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}

}

TransactionManagementConfigurationSelector类中只有一个方法,返回一个String数组,而数组中定义了两个类信息。且返回数组的值根据adviceMode的值来确定。回到@EnableTransactionManagement注解中,定义了一个属性:AdviceMode mode() default AdviceMode.PROXY ,默认是PROXY,所以这里默认给容器注入了两个组件:

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

下面就来看看这两个组件都做了什么:

AutoProxyRegistrar:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	private final Log logger = LogFactory.getLog(getClass());

	//注册、升级和配置标准自动代理创建器
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			if (candidate == null) {
				continue;
			}
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) { //注册自动代理创建器
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		if (!candidateFound) {
			String name = getClass().getSimpleName();
			logger.warn(String.format("%s was imported but no annotations were found " +
					"having both 'mode' and 'proxyTargetClass' attributes of type " +
					"AdviceMode and boolean respectively. This means that auto proxy " +
					"creator registration and configuration may not have occurred as " +
					"intended, and components may not be proxied as expected. Check to " +
					"ensure that %s has been @Import'ed on the same class where these " +
					"annotations are declared; otherwise remove the import of %s " +
					"altogether.", name, name, name));
		}
	}

}

AutoProxyRegistrar类的作用是注册一个自动代理创建器:AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry),而该方法默认情况下最终会给容器中注册一个:InfrastructureAdvisorAutoProxyCreator。InfrastructureAdvisorAutoProxyCreator是一个后置处理器,他的功能类似于Spring注解开启AOP功能中的AnnotationAwareAspectJAutoProxyCreator,有兴趣的朋友可以点进去看看,这里不再详细描述。

ProxyTransactionManagementConfiguration:

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

        //给容器注入BeanFactoryTransactionAttributeSourceAdvisor事物增强器
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());//设置事物属性信息
		advisor.setAdvice(transactionInterceptor()); //设置事物拦截器
		advisor.setOrder(this.enableTx.<Integer>getNumber("order")); //排序
		return advisor;
	}
        //注册事物的属性信息AnnotationTransactionAttributeSource
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

        //注册事物拦截器信息TransactionInterceptor
	@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;
	}

}

ProxyTransactionManagementConfiguration类被@Configuration标注,说明它是一个配置类,它给容器中注入一个事物增强器BeanFactoryTransactionAttributeSourceAdvisor,事物增强器中设置了事物的属性信息、事物拦截器和排序规则。其中事物的属性信息和事物的拦截器是注解管理事物的关键。

1、注册事物的注解信息:AnnotationTransactionAttributeSource

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

AnnotationTransactionAttributeSource:

	public AnnotationTransactionAttributeSource() {
		this(true);
	}


	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2); //保存注解的解析器
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}

AnnotationTransactionAttributeSource中可以注册三个注解的解析器:SpringTransactionAnnotationParser、JtaTransactionAnnotationParser、Ejb3TransactionAnnotationParser,每个注解解析器也就是利用反射实现注解的功能,可以解析注解中各个属性的值,并执行属性所表示的含义。因此这里可以获取到事物的注解信息。

2、注册事物的拦截器:TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
 
	public TransactionInterceptor() {
	}
 
	public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
		setTransactionManager(ptm);
		setTransactionAttributes(attributes);
	}
 
	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();
			}
		});
	}


	//---------------------------------------------------------------------
	// 序列化支持
	//---------------------------------------------------------------------

	private void writeObject(ObjectOutputStream oos) throws IOException {
		// 依赖于默认的序列化,
		oos.defaultWriteObject();

		// 超类字段进行反序列化。
		oos.writeObject(getTransactionManagerBeanName());
		oos.writeObject(getTransactionManager());
		oos.writeObject(getTransactionAttributeSource());
		oos.writeObject(getBeanFactory());
	}

	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 
		ois.defaultReadObject();
  
		setTransactionManagerBeanName((String) ois.readObject());
		setTransactionManager((PlatformTransactionManager) ois.readObject());
		setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
		setBeanFactory((BeanFactory) ois.readObject());
	}

}

从TransactionInterceptor类的源码中可以看出,该类实现了MethodIntercept接口。所以在目标方法执行的时候,他会执行拦截器链中的TransactionInterceptor,进行事物拦截。而TransactionInterceptor类中处理三个构造方法和两个私有的序列化方法,只有一个对外暴露的公共方法invoke()。而invoke方法的执行逻辑:先获取目标代理类信息,然后调用invokeWithinTransaction执行目标方法。

invokeWithinTransaction:

	protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {

		//先获取事物属性
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        //获取PlatformTransactionManager,默认按照类型获取一个PlatformTransactionManager
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        //获取事物方法
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			//如果需要,根据给定的TransactionAttribute创建事务。
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				//执行事物方法
				retVal = invocation.proceedWithInvocation();
			}catch (Throwable ex) {
				completeTransactionAfterThrowing(txInfo, ex);//异常回滚事物
				throw ex;
			}finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo); //正常结束事物方法,提交
			return retVal;
		}

		else {//CallbackPreferringPlatformTransactionManager:传入一个TransactionCallback。
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
							@Override
							public Object doInTransaction(TransactionStatus status) {
								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
								try {
									return invocation.proceedWithInvocation();
								}catch (Throwable ex) {
									if (txAttr.rollbackOn(ex)) {
										if (ex instanceof RuntimeException) {
											throw (RuntimeException) ex;
										}
										else {
											throw new ThrowableHolderException(ex);
										}
									}else {
										return new ThrowableHolder(ex);
									}
								}finally {
									cleanupTransactionInfo(txInfo);
								}
							}
						});

				// Check result: It might indicate a Throwable to rethrow.
				if (result instanceof ThrowableHolder) {
					throw ((ThrowableHolder) result).getThrowable();
				}else {
					return result;
				}
			}catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
		}
	}

invokeWithinTransaction方法的工作流程:

  1. 先获取事物属性
  2. 获取事物管理器PlatformTransactionManager ,如果没有指定则按照类型工容器总获取一个。
  3. 获取事物方法
  4. 执行事物方法,出现异常就回滚,正常结束就提交

至此,Spring完成了事物管理的功能。下面看一下Spring使用事物管理的注解@transactional:

@transactional:只是用于标注该方法将会被事物管理

@Transactional定义了多种属性,这里看一下它有哪些属性,作用是什么:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

	@AliasFor("transactionManager")
	String value() default "";

	//指定使用哪个事物管理器管理事物方法、类
	@AliasFor("value")
	String transactionManager() default "";

	//事务传播类型。共有7种
	Propagation propagation() default Propagation.REQUIRED;

	//事物隔离级别 
	Isolation isolation() default Isolation.DEFAULT;

	//事务的超时时间
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	//事物是否只读
	boolean readOnly() default false;

	//Spring 默认在出现RuntimeException和Error时回滚事物,这里可以自定义异常类型回滚事物
	Class<? extends Throwable>[] rollbackFor() default {};

	  //类似于rollbackFor属性,只不过这里的属性值是类名字符串,且不支持通配符如:
	 //{@code "ServletException"}将匹配{@code javax.servlet。及其子类。  
	String[] rollbackForClassName() default {};

	//定义哪些异常不会滚事物
	Class<? extends Throwable>[] noRollbackFor() default {};

	//定义哪些异常不会滚事物
	String[] noRollbackForClassName() default {};

}

@Transactional的属性中有两个属性propagation、isolation分别用来定义Spring事物的传播类型和事物的隔离级别。下面就看一下Spring事物的这两个属性的属性值信息:

事物传播类型:

事务的第一个方面是传播行为。传播行为定义关于客户端和被调用方法的事务边界。Spring定义了7中传播行为。

传播行为意义
PROPAGATION_MANDATORY表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。
PROPAGATION_NEVER表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。
PROPAGATION_REQUIRES_NEW表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_REQUIRED(默认传播行为)表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务。

传播规则回答了这样一个问题,就是一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行。

事物隔离级别:

隔离级别含义
ISOLATION_DEFAULT使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
ISOLATION_READ_COMMITTED允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。
ISOLATION_SERIALIZABLE完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。
  • 脏读(Dirty read)-- 脏读发生在一个事务读取了被另一个事务改写但尚未提交的数据时。如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的。
  • 不可重复读(Nonrepeatable read)-- 不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据。
  • 幻影读(Phantom reads)-- 幻影读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,幻影读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值