系列文章
spring 事务源码(三)如何保证被@Transactional标记方法中的所有sql都在一个事务内
前言
上文说到事务注解处理的切面如何注入、解析,这篇文章说下具体事务切面如何运行事务
测试代码
环境
jdk 1.8
spring boot 2.0.4
mybatis-plus-boot-starter 3.4.1
@Component
public class WebHelper {
@Autowired
CourseItemServiceImpl courseItemService;
@Transactional
public void test(){
courseItemService.getById(1);
}
}
源码
继上文结尾验证事务抛出堆栈异常,可以看到
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
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)) {
// 根据事务注解属性创建事务信息
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 最终调用@Transactional 注解的方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 事务执行异常处理,包含回滚操作
// 最终调用 DataSourceTransactionManager#doRollback
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
// 事务提交
// 最终调用 DataSourceTransactionManager#doCommit
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
......
// 事务管理器如果是CallbackPreferringPlatformTransactionManager运行此方法
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
...
}
}
事务管理器获取
org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// 如果没有事务属性,直接返回默认事务管理器
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
// 当前事务是否指定事务管理器
//形如:@Transactional(value = "wss")
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
// 从当前spring 容器中获取指定的事务管理器
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
// 目前不知道什么场景调用
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
// 大部分都是走这个
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
通过断点分析,默认的事务管理器是DataSourceTransactionManager
事务信息创建和初始化
org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
//.....
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 获取事务
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 事务准备
// 将事务绑定当前线程上下文
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
这是最核心的方法
org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 获取事务管理信息
Object transaction = doGetTransaction();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {
// 如果当前线程上下文已经存在事务,则根据事务注解的隔离级别处理
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 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);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事务 TransactionStatus
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务,提交sql
doBegin(transaction, definition);
// TransactionSynchronizationManager 相关属性处理
// 当前线程上下文事务属性初始化
prepareSynchronization(status, definition);
return status;
}
.....
}
else {
// 创建空事务,没有实际的事务处理但是也是创建 TransactionStatus
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);
}
}
下面主要说下org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 创建数据库链接
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 事务级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 如果设置主动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 在事务开始连接之前做预处理
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 在当前线程上下文绑定数据库链接持有信息
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
// 释放
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
总结
现在先缕缕大致的事务切面逻辑:
1.根据当前线程上下文中的事务管理器通过注解属性值创建事务
2.将当前事务信息绑定到线程上下文中
3.事务异常根据属性值是否回滚
4.事务执行结束提交