TransactionTemplate编程式事务

  • Post author:
  • Post category:其他



目录


一、TransactionTemplate相关源码

Spring支持编程式事务和声明式事务;
因为业务
  1.需要细粒度更高的事务控制;
  2.需要频繁与其他系统交互  

      举例:需要从A系统获取数据,根据获取的数据去跟B系统交互。整理处理完之后再与C系统交互。获取回执返回给A系统。与其他系统的交互掺杂在自己的业务代码中,如果用声明式事务对整个方法进行管控容易出现事务失效或者因系统通讯问题导致事务控制时间过长。

    所以工作中使用的是编程式事务(统一了事务种类,没有使用声明式事务)。图中绿框范围内的内容涉及到本地数据修改,需要用事务控制(绿框外的部分以数据传递为主,着重记录流水,这部分不纳入事务控制范围),也是业务重点,实际是以多线程方式与B系统交互,出现异常时用事务进行数据回滚和异常日志记录,并且不再执行后续的任务。
框架使用的是spring4.3.4.release版本。

一、TransactionTemplate相关源码

public class TransactionTemplate extends DefaultTransactionDefinition
		implements TransactionOperations, InitializingBean {

        // 定义事务控制器
        private PlatformTransactionManager transactionManager;

1)TransactionTemplate类

有三个主要方法:

1> afterPropertiesSet  bean实例化->生成对象->属性填充后进行了非空校验

2> execute 任务执行

3> rollbackOnException 回滚方法

一个成员变量:

transactionManager,对应PlatformTransactionManager事务控制器

——execute和rollbackOnException方法里的具体事务控制都是调用的PlatformTransactionManager里的接口方法(具体的事务管理受数据源影响)

public interface PlatformTransactionManager {
    //根据事务定义TransactionDefinition,获取事务
    TransactionStatus getTransaction(TransactionDefinition definition);
    //提交事务
    void commit(TransactionStatus status);
    //回滚事务
    void rollback(TransactionStatus status);
}

补充:由于扩展DefaultTransactionDefinition方法(DefaultTransactionDefinition实现了TransactionDefinition接口),因此TransactionTemplate可以设置事务传播属性、隔离级别信息。

a) 核心方法execute(TransactionCallback<T> action) ,(实现TransactionOperations接口)。

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
        } else {
            TransactionStatus status = this.transactionManager.getTransaction(this);

            Object result;
            try {
                result = action.doInTransaction(status);
            } catch (RuntimeException var5) {
                this.rollbackOnException(status, var5);
                throw var5;
            } catch (Error var6) {
                this.rollbackOnException(status, var6);
                throw var6;
            } catch (Throwable var7) {
                this.rollbackOnException(status, var7);
                throw new UndeclaredThrowableException(var7, "TransactionCallback threw undeclared checked exception");
            }

            this.transactionManager.commit(status);
            return result;
        }
    }

使用前需要private TransactionTemplate trsTemplate;注入TransactionTemplate事务模板

进而实现TransactionCallback<T>接口的T doInTransaction(TransactionStatus status);方法,通过匿名内部类的方式在doInTransaction里重写需要进行事务控制的业务代码即可。

补充:其实借助TransactionTemplate

.

execute(…)执行事务管理的时候,传入的参数有两种选择:

1.TransactionCallback

2.TransactionCallbackWithoutResult

前者有返回值,后者无返回值。两者一般是功能上对读写进行区分。当时项目统一了使用TransactionCallback。

 this.trsTemplate.execute(new TransactionCallback() {

            @Override
            public Object doInTransaction(TransactionStatus status) {
            	// 需要事务控制的业务代码
                }
                return null;
            }
        });

b) 事务异常回滚方法:

程序未出现异常时由this.transactionManager.commit(status);进行事务提交,出现异常并能够被程序捕获且处理时由this.rollbackOnException(status, var);进行回滚

private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
        this.logger.debug("Initiating transaction rollback on application exception", ex);

        try {
            this.transactionManager.rollback(status);
        } catch (TransactionSystemException var4) {
            this.logger.error("Application exception overridden by rollback exception", ex);
            var4.initApplicationException(ex);
            throw var4;
        } catch (RuntimeException var5) {
            this.logger.error("Application exception overridden by rollback exception", ex);
            throw var5;
        } catch (Error var6) {
            this.logger.error("Application exception overridden by rollback error", ex);
            throw var6;
        }
    }

二、事务

补充:Spring事务控制主要有下面三个部分

1.PlatformTransactionManager 事务控制器,spring事务管理的顶层接口(也是TransactionTemplate里使用的)

2.TransactionDefinition 事务基础信息 超时时间、隔离级别、传播属性等

3.TransactionStatus 事务运行状态信息 是否是新事务、是否已被标记为回滚等

1)PlatformTransactionManager事务控制器接口

public interface PlatformTransactionManager {
 
	//根据事务定义TransactionDefinition,获取事务
	TransactionStatus getTransaction(TransactionDefinition definition);
 
	//提交事务
	void commit(TransactionStatus status);
 
	//回滚事务
	void rollback(TransactionStatus status);
}

PlatformTransactionManager接口由AbstractPlatformTransactionManager抽象类实现,因为项目用的是mybatis和ibatis,所以实际使用的是对应子类DataSourceTransactionManage,相关代码挺多的,大致意思是如果没有传入事务定义就用默认定义DefaultTransactionDefinition;如果存在事务,那么进行事务传播属性处理,如果不存在事务就创建新事务并启用。

2)TransactionDefinition事务基础信息接口

之前1)中说的默认事务属性定义方法是DefaultTransactionDefinition实现的

public DefaultTransactionDefinition(TransactionDefinition other) {
		this.propagationBehavior = other.getPropagationBehavior();
		this.isolationLevel = other.getIsolationLevel();
		this.timeout = other.getTimeout();
		this.readOnly = other.isReadOnly();
		this.name = other.getName();
	}


    // 事务的传播属性  如果没有当前事务就新建,如果有就使用当前事务
    private int propagationBehavior = PROPAGATION_REQUIRED;

    // 事务的隔离级别  数据库默认的隔离级别
	private int isolationLevel = ISOLATION_DEFAULT;

    // 超时时间采用底层数据库默认的超时时间
	private int timeout = TIMEOUT_DEFAULT;

    // 是否只读为false
	private boolean readOnly = false;

	private String name;

补充

a).事务的隔离级别是数据库本身的事务功能,然而事务的传播属性则是Spring自己为我们提供的功能,数据库事务没有事务的传播属性这一说法

b).propagationBehavior常见枚举值

看看

详解事务的7种传播行为_砖业洋__的博客-CSDN博客_事务的传播行为

c)事务隔离级别待补充,不同数据库不一样,常见是下面几类

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量: T

TransactionDefinition.ISOLATION_DEFAULT:表示使用底层数据库的默认隔离级别。 TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。 TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。 TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。 TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

3.TransactionStatus事务运行状态信息接口

TransactionTemplate类里execute方法获取任务状态就调用AbstractPlatformTransactionManager的对应方法。

TransactionStatus status = this.transactionManager.getTransaction(this);
@Override
	public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}

		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException ex) {
				resume(null, suspendedResources);
				throw ex;
			}
			catch (Error err) {
				resume(null, suspendedResources);
				throw err;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

一般使用DefaultTransactionStatus实现TransactionStatus接口

可以参考

全面分析 Spring 的编程式事务管理及声明式事务管理_碧海凌云的博客-CSDN博客



版权声明:本文为lyh59原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。