Java中SpringBoot的@Transactional原理
一、@Transactional的使用
- 加在方法上:方法內(nèi)的所有操作處于一個事務中
- 加在類上
- 該類的所有public修飾的方法都具有共享事務屬性
- 如果方法和類上都有事務注解,方法上的事務注解優(yōu)先
二、@Transactional原理
Springboot目前最為流行,它的約定大于配置的特性深受大家喜歡,注解驅(qū)動開發(fā)已成為主流。面向元數(shù)據(jù)遍歷已經(jīng)成為越來越多開發(fā)者的偏好,因此原理從Springboot的EnableTransactionManagement注解說起
1、@EnableTransactionManagement
表示開啟事務管理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}通過Import導入了TransactionManagementConfigurationSelector類,其中默認的AdviceMode為AdviceMode.PROXY,即默認使用JDK的動態(tài)代理生成代理類。
2、TransactionManagementConfigurationSelector
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) {
//根據(jù)上面注解的默認配置,adviceMode默認為PROXY
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);
}
}TransactionManagementConfigurationSelector繼承自AdviceModeImportSelector類,實現(xiàn)selectImports方法可以注入對應的bean,根據(jù)EnableTransactionManagement注解的默認配置,adviceMode默認為PROXY。所以這里會注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration這兩個類
- AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* Register, escalate, and configure the standard auto proxy creator (APC) against the
* given registry. Works by finding the nearest annotation declared on the importing
* {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
* subclass (CGLIB) proxying.
* <p>Several {@code @Enable*} annotations expose both {@code mode} and
* {@code proxyTargetClass} attributes. It is important to note that most of these
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
* single APC}. For this reason, this implementation doesn't "care" exactly which
* annotation it finds -- as long as it exposes the right {@code mode} and
* {@code proxyTargetClass} attributes, the APC can be registered and configured all
* the same.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 這里面需要特別注意的是:這里是拿到所有的注解類型~~~而不是只拿@EnableAspectJAutoProxy這個類型的
// 原因:因為mode、proxyTargetClass等屬性會直接影響到代理得方式,而擁有這些屬性的注解至少有:
// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
// 甚至還有啟用AOP的注解:@EnableAspectJAutoProxy它也能設置`proxyTargetClass`這個屬性的值,因此也會產(chǎn)生關聯(lián)影響~
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
//獲取mode和proxyTargetClass的屬性
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
//如果存在這兩個屬性且類型符合要求
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
//向容器注入的是一個InfrastructureAdvisorAutoProxyCreator,它主要是讀取Advisor類,并對符合的bean進行二次代理
//如果出現(xiàn)多次的話,這里不是覆蓋的形式,而是以第一次的為主
//當然它內(nèi)部有做等級的提升之類的
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
//看要不要強制使用CGLIB的方式(這個屬性若出現(xiàn)多次,是會是覆蓋的形式)
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
//如果一個都沒有找到則打印info日志
//可能是自己注入這個類,而不是使用注解去注入
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}主要作用就是往Spring容器注入了一個自動代理創(chuàng)建器:org.springframework.aop.config.internalAutoProxyCreator,并且看看是采用CGLIB還是JDK代理
- ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@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;
}
@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;
}
}這里是往容器中注入事務相關的bean
- BeanFactoryTransactionAttributeSourceAdvisor:事務的核心,下面分析
- TransactionAttributeSource:事務屬性源
- TransactionInterceptor:事務攔截器,它是個MethodInterceptor。(我們可以自定義個beanName一模一樣的TransactionInterceptor來覆蓋默認的事務攔截器)
(我們可以自定義個beanName一模一樣的TransactionInterceptor來覆蓋默認的事務攔截器)
再看父類AbstractTransactionManagementConfiguration
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableTx;
/**
* Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
*/
@Nullable
protected TransactionManager txManager;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableTx = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
if (this.enableTx == null) {
throw new IllegalArgumentException(
"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
//這里可以通過配置文件注入一個默認的事務管理器
@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
//最多只允許配置一個
if (configurers.size() > 1) {
throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
}
TransactionManagementConfigurer configurer = configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
//注冊一個監(jiān)聽器工廠,用以支持@TransactionalEventListener注解標注的方法,來監(jiān)聽事務相關的事件
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
}- BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
//切面:決定了哪些類會被切入,從而生成的代理對象
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
// 可議手動設置一個事務屬性源
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
//可以指定ClassFilter 默認情況下:ClassFilter classFilter = ClassFilter.TRUE; 匹配所有的類的
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
//此處pointcut就是使用自己的這個pointcut去切入
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}我們繼續(xù)查看TransactionAttributeSourcePointcut類
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof TransactionAttributeSourcePointcut)) {
return false;
}
TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
}
@Override
public int hashCode() {
return TransactionAttributeSourcePointcut.class.hashCode();
}
@Override
public String toString() {
return getClass().getName() + ": " + getTransactionAttributeSource();
}
//由子類提供事務屬性源
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
/**
* {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
* for filtering classes whose methods are not worth searching to begin with.
*/
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
// 實現(xiàn)了如下三個接口的子類,就不需要被代理了 直接放行
// TransactionalProxy它是SpringProxy的子類。如果是被TransactionProxyFactoryBean生產(chǎn)出來的Bean,就會自動實現(xiàn)此接口,那么就不會被這里再次代理了
// PlatformTransactionManager:spring抽象的事務管理器
// PersistenceExceptionTranslator對RuntimeException轉(zhuǎn)換成DataAccessException的轉(zhuǎn)換接口
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
PlatformTransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
// 重要:拿到事務屬性源~~~~~~
// 如果tas == null表示沒有配置事務屬性源,那是全部匹配的,也就是說所有的方法都匹配
// 或者 標注了@Transaction這樣的注解的方法才會給與匹配
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}關于matches方法的調(diào)用時機:只要是容器內(nèi)的每個Bean,都會經(jīng)過AbstractAutoProxyCreator#postProcessAfterInitialization從而會調(diào)用wrapIfNecessary方法,因此容器內(nèi)所有的Bean的所有方法在容器啟動時候都會執(zhí)行此matche方法。
3、TransactionInterceptor
事務處理的核心邏輯就在這個攔截器里面,我們先看下Spring事務的三個接口
- TransactionStatus:代表一個事務的具體運行狀態(tài)、以及還原點
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
//判斷該事務里面是否含有還原點
boolean hasSavepoint();
//將基礎會話刷新到數(shù)據(jù)存儲
@Override
void flush();
}
public interface TransactionExecution {
//判斷當前的事務是否是新事務
boolean isNewTransaction();
//設置這個目的是為了讓事務的唯一結(jié)果是進行回滾。
//因此如果你在外層給try catche住不讓事務回滾,就會拋出你可能常見的異常:
//Transaction rolled back because it has been marked as rollback-only
void setRollbackOnly();
//判斷事務的是不是必須回滾
boolean isRollbackOnly();
//判斷事務是否結(jié)果(不管是commit還是rollback)
boolean isCompleted();
}- TransactionDefinition:用于描述隔離級別、超時時間、是否為只讀事務和事務傳播規(guī)則
- PlatformTransactionManager:事務管理器,包含
commit、rollback、getTransaction三個方法
根據(jù)上面的分析,我們知道TransactionInterceptor本質(zhì)就是一個MethodInterceptor,被事務攔截的方法最終都會執(zhí)行到此增強器身上。 MethodInterceptor是個環(huán)繞通知,敲好符合我們的開啟、提交、回滾事務等操作。
3.1、invoke方法
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
/**
* Create a new TransactionInterceptor.
* <p>Transaction manager and transaction attributes still need to be set.
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @see #setTransactionAttributeSource(TransactionAttributeSource)
*/
public TransactionInterceptor() {
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param attributes the transaction attributes in properties format
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
*/
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @see #setTransactionManager
* @see #setTransactionAttributeSource(TransactionAttributeSource)
*/
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
@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, invocation::proceed);
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void writeObject(ObjectOutputStream oos) throws IOException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
oos.defaultWriteObject();
// Deserialize superclass fields.
oos.writeObject(getTransactionManagerBeanName());
oos.writeObject(getTransactionManager());
oos.writeObject(getTransactionAttributeSource());
oos.writeObject(getBeanFactory());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
ois.defaultReadObject();
// Serialize all relevant superclass fields.
// Superclass can't implement Serializable because it also serves as base class
// for AspectJ aspects (which are not allowed to implement Serializable)!
setTransactionManagerBeanName((String) ois.readObject());
setTransactionManager((PlatformTransactionManager) ois.readObject());
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
setBeanFactory((BeanFactory) ois.readObject());
}
}其中invoke調(diào)用父類TransactionAspectSupport的invokeWithinTransaction方法
3.2、invokeWithinTransaction方法
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
/**
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
if (this.reactiveAdapterRegistry != null) {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException("Unsupported annotated transaction on suspending function detected: "
+ method + ". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter != null) {
return new ReactiveTransactionSupport(adapter).invokeWithinTransaction(method, targetClass, invocation);
}
}
//獲取事務屬性源
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);
// 如果txAttr為空或者tm屬于非CallbackPreferringPlatformTransactionManager,執(zhí)行目標增強
// 在TransactionManager上,CallbackPreferringPlatformTransactionManager實現(xiàn)PlatformTransactionManager接口,暴露出一個方法用于執(zhí)行事務處理中的回調(diào)
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//看是否有必要創(chuàng)建一個事務,根據(jù)事務傳播行為做出相應的判斷
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
try {
//回調(diào)方法執(zhí)行,執(zhí)行目標方法(原有的業(yè)務邏輯)
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 出現(xiàn)異常了,進行回滾(注意:并不是所有異常都會rollback的)
//如果出現(xiàn)的異常不需要rollback,則會進行commit
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除信息
cleanupTransactionInfo(txInfo);
}
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 目標方法完全執(zhí)行完成后,提交事務
commitTransactionAfterReturning(txInfo);
return retVal;
}
//編程式事務處理(CallbackPreferringPlatformTransactionManager) 會走這里
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
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.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
}邏輯很清晰,本質(zhì)就是通過try…catch…進行事務的提交或者回滾。我們看下里面的獲取事務管理器的方法determineTransactionManager
3.3、determineTransactionManager方法
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
//如果這兩個都沒配置,所以肯定是手動設置了PlatformTransactionManager的,那就直接返回即可
if (txAttr == null || this.beanFactory == null) {
return asPlatformTransactionManager(getTransactionManager());
}
//qualifier相當于beanName
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
//根據(jù)此名稱以及PlatformTransactionManager.class 去容器內(nèi)找bean
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
// 若沒有指定qualifier,那再看看是否指定了transactionManagerBeanName
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
//如果都沒指定,那就不管了。直接根據(jù)類型去容器里找 getBean(Class)
//注:如果容器里面有多個PlatformTransactionManager,那么就會導致報錯
else {
PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager(getTransactionManager());
if (defaultTransactionManager == null) {
defaultTransactionManager = asPlatformTransactionManager(
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;
}
}3.4、createTransactionIfNecessary
再看下創(chuàng)建事務的方法createTransactionIfNecessary,在看方法前,我們先看下返回的TransactionInfo類
protected static final class TransactionInfo {
// 當前事務的事務管理器
@Nullable
private final PlatformTransactionManager transactionManager;
// 當前事務的事務屬性
@Nullable
private final TransactionAttribute transactionAttribute;
//joinpoint標識
private final String joinpointIdentification;
// 當前事務的TransactionStatus
@Nullable
private TransactionStatus transactionStatus;
//保存當前事務所在的父事務上下文的引用,構(gòu)成了一個鏈,準確的說是一個有向無環(huán)圖
@Nullable
private TransactionInfo oldTransactionInfo;
public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
@Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
this.transactionManager = transactionManager;
this.transactionAttribute = transactionAttribute;
this.joinpointIdentification = joinpointIdentification;
}
public PlatformTransactionManager getTransactionManager() {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
return this.transactionManager;
}
@Nullable
public TransactionAttribute getTransactionAttribute() {
return this.transactionAttribute;
}
/**
* Return a String representation of this joinpoint (usually a Method call)
* for use in logging.
*/
public String getJoinpointIdentification() {
return this.joinpointIdentification;
}
//創(chuàng)建一個新的事務
public void newTransactionStatus(@Nullable TransactionStatus status) {
this.transactionStatus = status;
}
@Nullable
public TransactionStatus getTransactionStatus() {
return this.transactionStatus;
}
/**
* Return whether a transaction was created by this aspect,
* or whether we just have a placeholder to keep ThreadLocal stack integrity.
*/
public boolean hasTransaction() {
return (this.transactionStatus != null);
}
//綁定當前正在處理的事務的所有信息到ThreadLocal
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
//先從線程中拿出來老的,再把新的(也就是當前)綁定進去
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
//當前事務處理完之后,恢復父事務上下文
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
@Override
public String toString() {
return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
}
}然后再看創(chuàng)建事務的方法createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
//從事務管理器里,通過txAttr拿出來一個TransactionStatus
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");
}
}
}
//通過TransactionStatus 等,轉(zhuǎn)換成一個通用的TransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}再看方法prepareTransactionInfo
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
//構(gòu)造一個TransactionInfo
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
//把生成的TransactionInfo并綁定到當前線程的ThreadLocal
txInfo.bindToThread();
return txInfo;
}3.5、commitTransactionAfterReturning
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
//直接使用事務管理器提交事務
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}3.6、completeTransactionAfterThrowing
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
//如果有事務屬性了,那就調(diào)用rollbackOn看看這個異常需不需要回滾
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
//否則直接提交
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}3.7、cleanupTransactionInfo
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
//清除(解綁)事務
txInfo.restoreThreadLocalStatus();
}
}4、PlatformTransactionManager
事務管理器接口
public interface PlatformTransactionManager extends TransactionManager {
//創(chuàng)建事務
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
//提交事務
void commit(TransactionStatus status) throws TransactionException;
//回滾事務
void rollback(TransactionStatus status) throws TransactionException;
}4.1、AbstractPlatformTransactionManager
是對PlatformTransactionManager的一個抽象實現(xiàn),這個基類提供了以下工作流程處理
- 確定如果有現(xiàn)有的事務;
- 應用適當?shù)膫鞑バ袨?
- 如果有必要暫停和恢復事務;
- 提交時檢查rollback-only標記;
- 應用適當?shù)男薷漠敾貪L(實際回滾或設置rollback-only);
- 觸發(fā)同步回調(diào)注冊(如果事務同步是激活的)
(1)getTransaction方法
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
//如果沒有配置事務屬性,則使用默認的事務屬性
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
//獲取事務,具體的實現(xiàn)由具體的事務處理器提供
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
//檢查當前線程是否存在事務,如果是則直接處理已存在的事務,isExistingTransaction方法由子類去實現(xiàn)
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
//超時時間的校驗
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
//處理事務屬性中配置的事務傳播特性
// PROPAGATION_MANDATORY 如果已經(jīng)存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
//如果事務傳播特性為required、required_new或nested
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 掛起,doSuspend()由子類去實現(xiàn)
// 掛起操作,觸發(fā)相關的掛起注冊的事件,把當前線程事物的所有屬性都封裝好,放到一個SuspendedResourcesHolder
// 然后清空清空一下當前線程事務
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
//此處,開始創(chuàng)建事務
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//創(chuàng)建一個新的事務狀態(tài) 就是new DefaultTransactionStatus() 把個屬性都賦值上
DefaultTransactionStatus status = newTransactionStatus(
def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//開始事務,抽象方法,由子類去實現(xiàn)~
doBegin(transaction, def);
//初始化和同步事務狀態(tài)
prepareSynchronization(status, def);
return status;
}
catch (RuntimeException | Error ex) {
//重新開始 doResume由子類去實現(xiàn)
resume(null, suspendedResources);
throw ex;
}
}
// 走到這里表示傳播屬性就是不需要事務的,直接創(chuàng)建一個
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
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);
}
}(2)commit方法
@Override
public final void commit(TransactionStatus status) throws TransactionException {
//如果是一個已經(jīng)完成的事物,不可重復提交
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 如果已經(jīng)標記為了需要回滾,那就執(zhí)行回滾吧
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
// shouldCommitOnGlobalRollbackOnly這個默認值是false,目前只有JTA事務復寫成true了
// isGlobalRollbackOnly:是否標記為了全局的RollbackOnly
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
// 提交事務,會考慮到還原點、新事務、事務是否是rollback-only之類的
processCommit(defStatus);
}(3)rollback方法
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//交給子類去實現(xiàn)
processRollback(defStatus, false);
}4.2、DataSourceTransactionManager
以最為常用DataSourceTransactionManager作為實現(xiàn)類看看內(nèi)部具體如何實現(xiàn)
(1)doGetTransaction
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}(2)doBegin
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//從DataSource里獲取一個連接(這個DataSource一般是有連接池的)
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 把這個連接用ConnectionHolder包裝一下
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 設置isReadOnly、設置隔離界別等
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//這里非常的關鍵,先看看Connection 是否是自動提交的
//如果是 就con.setAutoCommit(false) 要不然數(shù)據(jù)庫默認沒執(zhí)行一條SQL都是一個事務,就沒法進行事務的管理了
//因此從這后面,通過此Connection執(zhí)行的所有SQL語句只要沒有commit就都不會提交給數(shù)據(jù)庫的
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
//這個方法特別特別有意思 它自己`Statement stmt = con.createStatement()`拿到一個Statement
// 然后執(zhí)行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
// 所以,所以:如果你僅僅只是查詢。把事務的屬性設置為readonly=true Spring對幫你對SQl進行優(yōu)化的
// 需要注意的是:readonly=true 后,只能讀,不能進行dml操作)(只能看到設置事物前數(shù)據(jù)的變化,看不到設置事物后數(shù)據(jù)的改變)
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) {
//如果是新創(chuàng)建的連接,那就釋放
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}(3)doCommit
@Override
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}到此這篇關于Java中SpringBoot的@Transactional原理的文章就介紹到這了,更多相關SpringBoot的@Transactional原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MybatisPlus 多租戶架構(gòu)(Multi-tenancy)實現(xiàn)詳解
這篇文章主要介紹了MybatisPlus 多租戶架構(gòu)(Multi-tenancy)實現(xiàn)詳解,詳細的介紹了什么是多租戶架構(gòu)以及使用MybatisPlus實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
SpringBoot啟動報錯屬性循環(huán)依賴報錯問題的解決
這篇文章主要介紹了SpringBoot啟動報錯屬性循環(huán)依賴報錯問題的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
java線程安全鎖ReentrantReadWriteLock原理分析readLock
這篇文章主要為大家介紹了java線程安全鎖ReentrantReadWriteLock原理分析readLock,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
Springcloud中Feign傳遞參數(shù)的過程解析
這篇文章主要介紹了Springcloud中Feign傳遞參數(shù)的過程,單個參數(shù)的傳值有兩種方式,第一種使用@RequestParam/@PathVariable進行傳值,傳遞多個參數(shù):多個參數(shù)的傳值可以使用多個@RequestParam來進行傳參,需要的朋友可以參考下2023-09-09

