coding++:Spring Boot全局事务解释及使用(一)
Spring 事务的入口:
TxAdviceBeanDefinitionParser 解释 <tx:advice/> 这里将解析tx的配置。 @Override protected Class<?> getBeanClass(Element element) { return TransactionInterceptor.class; },生成 TransactionInterceptor 对象, public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable 继承 TransactionAspectSupport 其中有个方法 invokeWithinTransaction() 特别重要:
invokeWithinTransaction():
//protected修饰,不允许其他包和无关类调用 protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // 获取对应事务属性.如果事务属性为空(则目标方法不存在事务) final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); // 根据事务的属性获取beanFactory中的PlatformTransactionManager(spring事务管理器的顶级接口),一般这里或者的是DataSourceTransactiuonManager final PlatformTransactionManager tm = determineTransactionManager(txAttr); // 目标方法唯一标识(类.方法,如service.UserServiceImpl.save) final String joinpointIdentification = methodIdentification(method, targetClass); //如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强 ① 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 { //清除信息 cleanupTransactionInfo(txInfo); } //提交事务 commitTransactionAfterReturning(txInfo); return retVal; } //编程式事务处理(CallbackPreferringPlatformTransactionManager) 不做重点分析 else { 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)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. 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(); } } }
spring事务架构:
但是在此之前,必须要知道的是spring事务的架构定义。
spring 事物管理高层抽象主要包括3个接口:
PlatformTransactionManager(事务管理器)
TransactionDefinition(事物定义信息)
TransactionStatus(事物具体运行状态)。
1、PlatformTransactionManager
重点说说 DataSourceTransactionManager,是否大家还记得这个类,在以前没继承springboot快速开发的时候,这个就是我们配置的事务管理器。
首先这个类继承了抽象类 AbstractPlatformTransactionManager
这个类中,比较重要的是:
1):getTransaction()获取事务,在源码中是这样解释:
根据,返回当前活动的事务或创建一个新的事务指定的传播行为。
注意,隔离级别或超时等参数只会被应用用于新事务,因此在参与活动事务时将被忽略。
此外,不是所有的事务定义设置将被支持,每个事务管理器:一个正确的事务管理器实现.当遇到不支持的设置时,应该抛出异常。
上面规则的一个例外是只读标志,它应该是只读的.如果不支持显式只读模式,则忽略。本质上讲,只读标志只是潜在优化的一个提示。
2):commit(TransactionStatus status)方法,事务提交(回滚、提交):
其中遇到做多的坑,基本就是这个 Transaction rolled back because it has been marked as rollback-only
这个在方法命名时,需要注意方法命名规范(例如:查询就使用get,query等),以及在查询操作和更改操作的时候,抛异常时,需要特别注意事务的传播级别。
在方法 processCommit(defStatus);中有一个特别重要的代码:
主要的作用是无论成功与否都释放当前事务,以下是 DataSourceTransactionManager 的实现:
@Override protected void doCleanupAfterCompletion(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; // Remove the connection holder from the thread, if exposed. if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.unbindResource(this.dataSource); } // Reset connection. Connection con = txObject.getConnectionHolder().getConnection(); try { if (txObject.isMustRestoreAutoCommit()) { con.setAutoCommit(true); } DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()); } catch (Throwable ex) { logger.debug("Could not reset JDBC Connection after transaction", ex); } if (txObject.isNewConnectionHolder()) { if (logger.isDebugEnabled()) { logger.debug("Releasing JDBC Connection [" + con + "] after transaction"); } DataSourceUtils.releaseConnection(con, this.dataSource); } txObject.getConnectionHolder().clear(); }
2、Transactiondefinition事务传播行为:
spring 在 TransactionDefinition 接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:
事务传播行为类型 事务传播行为类型 说明 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
3、TransactionStatus