1、主要是讨论在与Mybatis结合的时候事务的控制是怎么实现的
讲几个大前提,spring的事务管理是基于aop实现的,那么可以理解为,在开启事务后,spring提供一些必要的对原方法的增强,即事务相关的处理,增强原方法。
1、在springboot中使用事务管理时,首先会使用这个注解@EnableTransactionManagement
那么这个注解起了什么作用?在实现事务控制的过程中发挥了什么作用?
最关键的就是这个Import,Import的作用,可以暂时理解为引入,我们可以认为,引入的这个类会被做一些处理,以达到一些目的。那么继续看看引入的这个类包含了什么内容。此前,可以从引入的这个类的名字看出这是个事务管理配置选择器。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
简单来说就是一个AbstractTransactionManagementConfiguration选择器,selectImports方法,根据参数选择不同的事务管理配置。实际中是PROXY模式。
这里讲一些其他的事情,这个类TransactionManagementConfigurationSelector是通过Import注解引入的,在某个时机会处理通过Import注解导入的类。这个类的父类实现了这个接口ImportSelector,在处理TransactionManagementConfigurationSelector时,发现他实现了ImportSelector接口,会调用selectImports接口,返回要导入的内容。 我们看这里会返回什么?
进入PROXY分支,返回了
- AutoProxyRegistrar.class.getName()
- ProxyTransactionManagementConfiguration.class.getName()
下面看看这两个东西是什么?
- AutoProxyRegistrar 实现了ImportBeanDefinitionRegistrar,会注入BeanDefinition(代理创建器)
- ProxyTransactionManagementConfiguration 就是个普通的类,也会把它注入容器中
重点看下ProxyTransactionManagementConfiguration这个类究竟都有什么?
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 顾名思义,一个advisor就是增强器
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
// 用来获取@transactinal注解信息的工具
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// ?
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
重点是看看advisor在什么时候起的作用,以及起的什么作用。最终就是aop把目标方法代理了。这个advisor就是事务处理的部分了,更多的细节就是aop是怎么做的里面了。
spring事务的传播
spring事务的传播指的是
a(){
b();
}
即在方法中又调用方法的 这两个方法之间的传播。
3、spring的事务管理究竟是怎么运行的?
在只使用jdbc时事务是这样使用
- 1、获取一个connection
- 2、设置这个connection手动提交,即自动提交为false
- 3、在执行完操作后,commit或rollback
那在spring中管理事务也一定离不开这三步,但在spring中因为操作因为聚合多个系统产生了一定的复杂性,但总体还是这个过程。
3.1、上述被称为核心流程
那么先看看在spring中核心流程是怎么处理的。
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 这里很简单 就是获取一个connection,但是可以看到这里有一个connecHolder
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);
设置是否只读
txObject.setReadOnly(definition.isReadOnly());
// 设为手动提交事务
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 如果是只读模式就使用SET TRANSACTION READ ONLY这个sql设置一下
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 将connection绑定到当前线程,使用ThreadLocal
// Bind the connection holder to the thread.
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);
}
}
经过这个方法,就完成这个核心流程