1、引言
spring的spring-tx模块提供了对事务管理反对,应用spring事务能够让咱们从简单的事务处理中失去解脱,无须要去解决取得连贯、敞开连贯、事务提交和回滚等这些操作。
spring事务有编程式事务和申明式事务两种实现形式。编程式事务是通过编写代码来治理事务的提交、回滚、以及事务的边界。这意味着开发者须要在代码中显式地调用事务的开始、提交和回滚。申明式事务是通过配置来治理事务,您能够应用注解或XML配置来定义事务的边界和属性,而无需显式编写事务管理的代码。
上面咱们逐渐剖析spring源代码,了解spring事务的实现原理。
2、编程式事务
2.1 应用示例
// transactionManager是某一个具体的PlatformTransactionManager实现类的对象
private PlatformTransactionManager transactionManager;
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 获取事务
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行数据库操作
// ...
// 提交事务
transactionManager.commit(status);
} catch (Exception ex) {
// 回滚事务
transactionManager.rollback(status);
}
在应用编程式事务处理的过程中,利用 DefaultTransactionDefinition 对象来持有事务处理属性。同时,在创立事务的过程中失去一个 TransactionStatus 对象,而后通过间接调用 transactionManager 对象 的 commit() 和 rollback()办法 来实现事务处理。
2.2 PlatformTransactionManager外围接口
PlatformTransactionManager是Spring事务管理的外围接口,通过 PlatformTransactionManager 接口设计了一系列与事务处理非亲非故的接口办法,如 getTransaction()、commit()、rollback() 这些和事务处理相干的对立接口。对于这些接口的实现,很大一部分是由 AbstractTransactionManager 抽象类来实现的。
AbstractPlatformManager 封装了 Spring 事务处理中通用的解决局部,比方事务的创立、提交、回滚,事务状态和信息的解决,与线程的绑定等,有了这些通用解决的反对,对于具体的事务管理器而言,它们只须要解决和具体数据源相干的组件设置就能够了,比方在DataSourceTransactionManager中,就只须要配置好和DataSource事务处理相干的接口以及相干的设置。
2.3 事务的创立
PlatformTransactionManager的getTransaction()办法,封装了底层事务的创立,并生成一个 TransactionStatus对象。AbstractPlatformTransactionManager提供了创立事务的模板,这个模板会被具体的事务处理器所应用。从上面的代码中能够看到,AbstractPlatformTransactionManager会依据事务属性配置和以后过程绑定的事务信息,对事务是否须要创立,怎么创立 进行一些通用的解决,而后把事务创立的底层工作交给具体的事务处理器实现,如:DataSourceTransactionManager、HibernateTransactionManager。
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
if (isExistingTransaction(transaction)) {
return handleExistingTransaction(def, transaction, debugEnabled);
}
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
return startTransaction(def, transaction, false, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = this.getTransactionSynchronization() != SYNCHRONIZATION_NEVER;
DefaultTransactionStatus status = this.newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
this.doBegin(transaction, definition);
this.prepareSynchronization(status, definition);
return status;
}
事务创立的后果是生成一个TransactionStatus对象,通过这个对象来保留事务处理须要的根本信息,TransactionStatus的创立过程如下:
protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
boolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive();
return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.isReadOnly(), debug, suspendedResources);
}
以上是创立一个全新事务的过程,还有另一种状况是:在创立以后事务时,线程中曾经有事务存在了。这种状况会波及事务流传行为的解决。spring中七种事务流传行为如下:
| 事务流传行为类型 | 阐明 |
| PROPAGATION_REQUIRED | 如果以后没有事务,就新建一个事务,如果曾经存在一个事务中,退出到这个事务中。这是最常见的抉择。 |
| PROPAGATION_SUPPORTS | 反对以后事务,如果以后没有事务,就以非事务形式执行。 |
| PROPAGATION_MANDATORY | 应用以后的事务,如果以后没有事务,就抛出异样。 |
| PROPAGATION\_REQUIRES\_NEW | 新建事务,如果以后存在事务,把以后事务挂起。 |
| PROPAGATION\_NOT\_SUPPORTED | 以非事务形式执行操作,如果以后存在事务,就把以后事务挂起。 |
| PROPAGATION_NEVER | 以非事务形式执行,如果以后存在事务,则抛出异样。 |
| PROPAGATION_NESTED | 如果以后存在事务,则在嵌套事务内执行。如果以后没有事务,则执行与PROPAGATION_REQUIRED相似的操作。 |
如果检测到已存在事务,handleExistingTransaction()办法将依据不同的事务流传行为类型执行相应逻辑。
PROPAGATION_NEVER
即以后办法须要在非事务的环境下执行,如果有事务存在,那么抛出异样。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
PROPAGATION\_NOT\_SUPPORTED
与前者的区别在于,如果有事务存在,那么将事务挂起,而不是抛出异样。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
PROPAGATION\_REQUIRES\_NEW
新建事务,如果以后存在事务,把以后事务挂起。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
SuspendedResourcesHolder suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
PROPAGATION_NESTED
开始一个 “嵌套的” 事务, 它是曾经存在事务的一个真正的子事务. 嵌套事务开始执行时, 它将获得一个 savepoint. 如果这个嵌套事务失败, 咱们将回滚到此 savepoint. 嵌套事务是内部事务的一部分, 只有内部事务完结后它才会被提交。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (useSavepointForNestedTransaction()) {
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, false, false, true, debugEnabled, null);
this.transactionExecutionListeners.forEach(listener -> listener.beforeBegin(status));
try {
status.createAndHoldSavepoint();
}
catch (RuntimeException | Error ex) {
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, ex));
throw ex;
}
this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, null));
return status;
}
else {
return startTransaction(definition, transaction, true, debugEnabled, null);
}
}
2.4 事务挂起
事务挂起在AbstractTransactionManager.suspend()中解决,该办法外部将调用具体事务管理器的doSuspend()办法。以DataSourceTransactionManager为例,将ConnectionHolder设为null,因为一个ConnectionHolder对象就代表了一个数据库连贯,将ConnectionHolder设为null就意味着咱们下次要应用连贯时,将从新从连接池获取。
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
unbindResource()办法最终会调用TransactionSynchronizationManager.doUnbindResource()办法,该办法将移除以后线程与事务对象的绑定。
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
if (value instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
value = null;
}
return value;
}
而被挂起的事务的各种状态最终会保留在TransactionStatus对象中。
2.5 事务提交&回滚
次要是对jdbc的封装、源码逻辑较清晰,不开展细说。
3、申明式事务
其底层建设在 AOP 的根底之上,对办法前后进行拦挡,而后在指标办法开始之前创立或者退出一个事务,在执行完指标办法之后依据执行状况提交或者回滚事务。通过申明式事物,无需在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相干的事务规定申明(或通过等价的基于标注的形式),便能够将事务规定利用到业务逻辑中。
3.1 应用示例
配置:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
代码:
@Transactional
public void addOrder() {
// 执行数据库操作
}
3.2 自定义标签解析
先从配置文件开始动手,找到解决annotation-driven标签的类TxNamespaceHandler。TxNamespaceHandler实现了NamespaceHandler接口,定义了如何解析和解决自定义XML标签。
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
AnnotationDrivenBeanDefinitionParser里的parse()办法,对XML标签annotation-driven进行解析。
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
以默认mode配置为例,执行configureAutoProxyCreator()办法,将在Spring容器中注册了3个bean:
BeanFactoryTransactionAttributeSourceAdvisor、TransactionInterceptor、AnnotationTransactionAttributeSource。同时会将TransactionInterceptor的BeanName传入到Advisor中,而后将AnnotationTransactionAttributeSource这个Bean注入到Advisor中。之后动静代理的时候会应用这个Advisor去寻找每个Bean是否须要动静代理。
// Create the TransactionAttributeSourceAdvisor definition.
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
3.3 Advisor
回顾AOP用法,Advisor可用于定义一个切面,它蕴含切点(Pointcut)和告诉(Advice),用于在特定的连接点上执行特定的操作。spring事务实现了一个Advisor: BeanFactoryTransactionAttributeSourceAdvisor。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.pointcut.setTransactionAttributeSource(transactionAttributeSource);
}
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
BeanFactoryTransactionAttributeSourceAdvisor其实是一个PointcutAdvisor,是否匹配到切入点取决于Pointcut。Pointcut的外围在于其ClassFilter和MethodMatcher。
ClassFilter:
TransactionAttributeSourcePointcut外部公有类 TransactionAttributeSourceClassFilter,实现了Spring框架中的ClassFilter接口。在matches办法中,它首先查看传入的类clazz 否为TransactionalProxy、TransactionManager或PersistenceExceptionTranslator的子类,如果不是,则获取以后的 TransactionAttributeSource 并查看其是否容许该类作为候选类。
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
return (transactionAttributeSource == null || transactionAttributeSource.isCandidateClass(clazz));
}
}
MethodMatcher:
TransactionAttributeSourcePointcut.matches:
@Override
public boolean matches(Method method, Class<?> targetClass) {
return (this.transactionAttributeSource == null ||
this.transactionAttributeSource.getTransactionAttribute(method, targetClass) != null);
}
getTransactionAttribute()办法最终会调用至AbstractFallbackTransactionAttributeSource.computeTransactionAttribute()办法,该办法将先去办法上查找是否有相应的事务注解(比方@Transactional),如果没有,那么再去类上查找。
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow non-public methods, as configured.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
3.4 TransactionInterceptor
TransactionInterceptor是spring事务提供的AOP拦截器,实现了AOP Alliance的MethodInterceptor接口,是一种告诉(advice)。其能够用于在办法调用前后进行事务管理。
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
invokeWithinTransaction()办法会依据指标办法上的事务配置,来决定是开启新事务、退出已有事务,还是间接执行逻辑(如果没有事务)。其代码简化如下(仅保留PlatformTransactionManager局部):
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) {
// 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);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
ObjectretVal = 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 (Throwableex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throwex;
} finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
returnretVal;
}
}
作者:京东批发 范锡军
起源:京东云开发者社区 转载请注明起源
发表回复