spring(六):事务

事务特性ACID

  • 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
  • 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏。
  • 隔离性(Isolation):并发事务执行之间无影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;
  • 持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。

常见的问题

  • 丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的
  • 脏读:一个事务看到了另一个事务未提交的更新数据
  • 不可重复读:在同一事务中,多次读取同一数据却返回不同的结果(也就是有其他事务更改了这些数据)
  • 幻读:一个事务在执行过程中读取到了另一个事务已提交的插入数据(即在第一个事务开始时读取到一批数据,但此后另一个事务又插入了新数据并提交,此时第一个事务又读取这批数据但发现多了一条,即好像发生幻觉一样)

事务隔离级别

  • 未提交读(Read Uncommitted):最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;
  • 提交读(Read Committed):一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读;
  • 可重复读(Repeatable Read):保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,可能可能出现丢失更新、脏读、不可重复读,但可能出现幻读;
  • 序列化(Serializable):最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读。

隔离级别越高,数据库事务并发执行性能越差,能处理的操作越少。在实际项目开发中为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。

事务管理器

Spring框架支持事务管理的核心是事务管理器,通过实现策略接口PlatformTransactionManager支持各种数据访问框架的事务管理。

Spring 支持两种类型的事务管理:

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。
  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。
public interface PlatformTransactionManager {
    // 根据给定的TransactionDefinition类型参数获取一个已经激活的事务或创建一个新的事务
    // 返回值TransactionStatus对象代表了当前事务的状态
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    // 提交TransactionStatus参数代表的事务
    void commit(TransactionStatus var1) throws TransactionException;
    // 回滚TransactionStatus参数代表的事务
    void rollback(TransactionStatus var1) throws TransactionException;
}
public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;	// 支持当前事务;如果不存在事务,则创建一个新的事务。
    int PROPAGATION_SUPPORTS = 1;	// 支持当前事务;如果不存在,则执行非事务性。
    int PROPAGATION_MANDATORY = 2;	// 支持当前事务;如果不存在当前事务,则抛出一个异常。
    int PROPAGATION_REQUIRES_NEW = 3;	// 创建一个新事务,如果存在一个事务,则把当前事务挂起。
    int PROPAGATION_NOT_SUPPORTED = 4;	// 不支持当前事务;而总是执行非事务性。
    int PROPAGATION_NEVER = 5;		// 不支持当前事务;如果存在当前事务,则抛出一个异常。
    int PROPAGATION_NESTED = 6;		// 如果存在当前事务,则在一个嵌套的事务中执行。
    
    int ISOLATION_DEFAULT = -1;		// 这是默认的隔离级别。
    int ISOLATION_READ_UNCOMMITTED = 1;	// 表明可以发生误读、不可重复读和虚读。
    int ISOLATION_READ_COMMITTED = 2;	// 表明能够阻止误读;可以发生不可重复读和虚读。
    int ISOLATION_REPEATABLE_READ = 4;	// 表明能够阻止误读和不可重复读;可以发生虚读。
    int ISOLATION_SERIALIZABLE = 8;		// 表明能够阻止误读、不可重复读和虚读。
    
    int TIMEOUT_DEFAULT = -1;
    
    int getPropagationBehavior();	// 获取事务传播行为
    int getIsolationLevel();	// 获取事务隔离级别
    int getTimeout();	// 获取事务超时时间
    boolean isReadOnly();	// 获取事务是否是只读的
    @Nullable
    String getName();  	// 获取事务名字
}  
public interface TransactionStatus extends SavepointManager, Flushable {
    boolean isNewTransaction();	// 当前事务状态是否是新事务
    boolean hasSavepoint();	// 当前事务是否有保存点
    void setRollbackOnly();	// 设置当前事务应该回滚
    boolean isRollbackOnly();	// 当前事务是否应该回滚
    void flush();	// 刷新底层会话中的修改到数据库
    boolean isCompleted();	// 当前事务否已经完成
}

声明式事务处理的实现分析

声明式事务的实现就是通过环绕增强的方式,在目标方法执行之前开启事务,在目标方法执行之后提交或者回滚事务。

  1. 读取和处理在IoC容器中配置的事务处理属性,并转化为事务处理幼的数据结构(TransactionAttribute)(使用通知器TransactionAttributeSourceAdvisor来完成事务处理属性的处理,和TransactionProxyFactoryBean拦截下来的事务方法的处理结合起来)
  2. 实现统一的事务处理过程,包含处理事务配置属性和与线程绑定完成事务处理的过程。(TransactionInfo和TransactionStatus记录和传递相关执行场景)
  3. 底层的事务处理实现。即PlatformTransactionManager接口的具体实现。

事务处理拦截器的配置

// TransactionProxyFactoryBean	
	@Override
	// 在IoC容器完成bean的依赖注入时,通过bean的初始化方法被调用
	// 自此,transactionInterceptor配置被启动并成为通知器Advisor的一部分
	protected Object createMainInterceptor() {
		...
		if (this.pointcut != null) {
			return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
		}
		else {
			// Rely on default pointcut.
			return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
		}
	}
// AbstractSingletonProxyFactoryBean
	// 是事务处理完成aop配置的地方
    public void afterPropertiesSet() {
        // 检测bean
        ...else {
            ...
            // 创建代理工厂对象
            ProxyFactory proxyFactory = new ProxyFactory();
            // 为ProxyFactory生成代理对象、配置通知器、设置代理接口
            // 自此,拦截器被配置进代理对象中
            proxyFactory.addAdvisor(...);
            ...
            proxyFactory.setInterfaces(...);
            this.postProcessProxyFactory(proxyFactory);
            this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
        }
    }

事务处理配置的读入

在TransactionInterceptor进行依赖注入时,其父类TransactionAspectSupport设置TransactionAttribute。

	public void setTransactionAttributes(Properties transactionAttributes) {
		NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
		tas.setProperties(transactionAttributes);
		this.transactionAttributeSource = tas;
	}
	public void setProperties(Properties transactionAttributes) {
		TransactionAttributeEditor tae = new TransactionAttributeEditor();
		Enumeration<?> propNames = transactionAttributes.propertyNames();
		while (propNames.hasMoreElements()) {
			String methodName = (String) propNames.nextElement();
			String value = transactionAttributes.getProperty(methodName);
			tae.setAsText(value);
			TransactionAttribute attr = (TransactionAttribute) tae.getValue();
			addTransactionalMethod(methodName, attr);
		}
	}

事务处理拦截器的设计与实现

// TransactionInterceptor	
	@Override
	@Nullable
	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...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
// TransactionAspectSupport	
	@Nullable
	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 PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
            // 创建事务 ★
			TransactionInfo txInfo = createTransactionIfNecessary(tm, 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();
			}...
			finally {
                // 事务信息更新
				cleanupTransactionInfo(txInfo);
			}
            // 提交事务<<PlatformTransactionManager>>
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
					try {
						return invocation.proceedWithInvocation();
					}
					catch (Throwable ex) {
						if (txAttr.rollbackOn(ex)) {
							// A RuntimeException: will lead to a rollback.
							...
						}
						else {
							// A normal return value: will lead to a commit.
							...
						}
					}
					finally {
						cleanupTransactionInfo(txInfo);
					}
				});

				// Check result state: It might indicate a Throwable to rethrow.
				...
				return result;
			}
			...
		}
	}

	protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// If no name specified, apply method identification as transaction name.
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
                // 获取事务对象,创建TransactionStatus对象
				status = tm.getTransaction(txAttr);
			}
			...
		}
        // 把TransactionStatus设置到TransactionInfo中,并绑定到当前线程
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

posted @ 2019-07-16 15:21  白芷呀  阅读(238)  评论(0编辑  收藏  举报