spring 事务部分共5篇文章
第一篇:spring中@EnableTransactionManager @Transactional注解实现机制
第二篇:spring boot中事务功能自动配置的加载过程分析
第三篇:spring@Transactional注解属性字段含义
第四篇:spring @Transactional如何测试事务注解生效
第五篇:spring及spring boot中事务相关知识的总结
本篇为第一篇
先提出几个问题
1. 为什么在spring中加入了@EnableTransactionManagement就会开启事务支持呢?
2. @EnableTransactionManagement与@Transactional是如何配合以实现事务效果的呢?
3. spring中的方法与mysql中真正的事务执行语句是如何对应起来的?
4. @Transactional注解的处理,以及拦截器将代理织入,事务执行的时候通过代理对象来执行,这块的源码是怎样的
1. @EnableTransactionManagement作用
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
默认adviceMode是PROXY
利用TransactionManagementConfigurationSelector给容器中会导入组件
导入两个组件AutoProxyRegistrar及ProxyTransactionManagementConfiguration
2. AutoProxyRegistrar的作用--注册InfrastructureAdvisorAutoProxyCreator 组件
给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
org.springframework.context.annotation.AutoProxyRegistrar#registerBeanDefinitions
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
InfrastructureAdvisorAutoProxyCreator
类图
其与spring aop中的AnnotationAwareAutoProxyCreator的BeanPostProcessor非常类似
原理也是:利用InfrastructureAdvisorAutoProxyCreator后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器)
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
如我们在EmployeeService中的saveTwoEmployee方法上添加了@Transactional注解
这里我们就可以看到,容器中employeeService这个bean在初始化阶段就已经被InfrastructureAdvisorAutoProxyCreator这个BeanPostProcessor包装为代理对象了,以后从容器中取出的这个singleton bean都是代理对象
查看CGLIB$CALLBACK_0
可以看到其织入了三个切面,前两个是DruidStatInterceptor,最后一个是TransactionInterceptor
如果想了解BeanPostProcessor是如何包装对象使其成为代理对象的,参考:
spring aop源码解析1: 创建、初始化并注册AnnotationAwareAspectJAutoProxyCreator
3. ProxyTransactionManagementConfiguration作用
其是一个@Configuration配置类,来给容器中注册@Bean组件
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {}
注册事务增强器
在ProxyTransactionManagementConfiguration中,注册了transactionAdvisor bean
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 为Advisor添加Advice,Advice就是transactionInterceptor
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
事务属性类也是一个@Bean
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#AnnotationTransactionAttributeSource(boolean)
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
}
在这里创建一个自定义的AnnotationTransactionAttributeSource,支持带有@Transactional注释的public方法
org.springframework.transaction.annotation.SpringTransactionAnnotationParser
在SpringTransactionAnnotationParser#parseTransactionAnnotation方法中处理@Transactional注解
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
解析@Transactional中的每一个信息,封装到AnnotationAttributes对象中
事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析@Transactional注解
注册事务拦截器
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
注册了transactionInterceptor bean
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
TransactionInterceptor;保存了事务属性信息,事务管理器;
其是一个 MethodInterceptor;
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
}
invoke方法调用
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
来处理commit及rollback
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
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 = null;
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();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
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();
}
}
}
4. 执行目标方法(执行拦截器链)
目标方法执行的时候,执行拦截器链;
先看一下整体的流程图
spring事务中拦截器触发过程流程图:
构造拦截器链
容器中保存了组件如employeeService的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象等)
CglibAopProxy.intercept();拦截目标方法的执行
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor
其拦截器链(项目中使用了druid连接池)
获取事务相关的属性
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
获取PlatformTransactionManager
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager
protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
// 如果我们在@Transactional中指定TransactionalManager(qualifier)
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
}
// 如果没有指定,那么最终会从容器中按照类型获取一个PlatformTransactionManager;
// 如果是jdbc,那么就使用DataSourceTransactionManager
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;
}
}
如果我们在@Transactional中指定TransactionalManager(qualifier)
如果没有指定,那么最终会从容器中按照类型获取一个PlatformTransactionManager;
如果是jdbc,那么就使用DataSourceTransactionManager
如果是jpa,那么就使用JpaTransactionManager
获取到的transactionManager
获取切点
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
执行织入的增强方法和目标方法
代理对象执行目标方法时执行拦截器链
前两个druidStatInterceptor就不关心了
直接看TransactionalInterceptor的invoke方法
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
先将connection的autoCommit设置为false
begin transaction;
之后设置@Transactional注解的属性,如isolation,rollback等
之后开始执行真正的目标方法,执行多条sql语句
retVal = invocation.proceedWithInvocation();
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();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
如果异常,那么通过调用completeTransactionAfterThrowing
获取到事务管理器,利用事务管理回滚操作;
如果正常,调用commitTransactionAfterReturning
利用事务管理器,提交事务
5. 通过console查看事务实际执行过程
为了查看事务执行的过程,要在applicationContext.properties中开启
logging.level.org.springframework.transaction=trace
1. 识别到@Transactional注解
调用二次
一次是SimpleJpaRepository类上的注解
另一次是save方法上的注解(覆盖了类上的注解)
2. addEmp
3. saveEmpLog
4. 方法结束时再调用一次
注意:
如果执行的是update tbl_employee操作,不是前面的insert tbl_employee操作,其sql的执行过程是这样的
前两步还是一样的
第三步只有一条select语句
第四步相同
第五步来执行update tbl_employee