• 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);
    	}
    
    
  • 相关阅读:
    Hz赫兹的定义
    NetCore 迅速接入微信支付+支付宝支付 payLink C# 交差并集
    C# 生产随机数 --几乎可以做到不重复
    Spark MLib完整基础入门教程
    (转)Scrapy 教程
    (转)python自顶向下设计步骤_python实现自顶向下,自底向上
    (转)scrapy架构图与执行流程
    (转)Python:字典(zip, dict)
    (转)APUE第13章 守护进程Deameon
    (转)Python开发指南
  • 原文地址:https://www.cnblogs.com/angelica-duhurica/p/11195133.html
Copyright © 2020-2023  润新知