1. 程式人生 > >Spring的事物原理

Spring的事物原理

不一致 tst atom 默認 讀數 transacti sdn pla 常用

在Spring中把非功能性的事物管理代碼以切面的形式進行管理,只需要聲明事物即可啟用事物管理。

本質:最終執行的還是java.sql.Connection的setAutoCommit(),commit(),rollback()方法。

技術分享圖片

事物管理器接口:PlatformTransactionManager.java

package org.springframework.transaction;

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
    void commit(TransactionStatus var1) throws TransactionException;
    void rollback(TransactionStatus var1) throws TransactionException;
}

事物管理器實現:DataSourceTransactionManager.java

主要操作的是DataSource

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
    private DataSource dataSource;
    public DataSourceTransactionManager(DataSource dataSource) {
        this();
        this.setDataSource(dataSource);
        this.afterPropertiesSet();
    }
    // 提交的實現
    protected void doCommit(DefaultTransactionStatus status) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            this.logger.debug("Committing JDBC transaction on Connection [" + con + "]");
        }

        try {
            con.commit();
        } catch (SQLException var5) {
            throw new TransactionSystemException("Could not commit JDBC transaction", var5);
        }
    }

    // 回滾的實現
    protected void doRollback(DefaultTransactionStatus status) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
        }

        try {
            con.rollback();
        } catch (SQLException var5) {
            throw new TransactionSystemException("Could not roll back JDBC transaction", var5);
        }
    }
}

事物定義:TransactionDefinition.java

package org.springframework.transaction;

public interface TransactionDefinition {
    // 傳播行為
    int PROPAGATION_REQUIRED = 0;//默認事物傳播行為
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    // 隔離級別
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    int getPropagationBehavior();
    int getIsolationLevel();
    int getTimeout();
    boolean isReadOnly();
    String getName();
}

事物狀態:TransactionStatus.java

public interface TransactionStatus extends SavepointManager, Flushable {
    boolean isNewTransaction();
    boolean hasSavepoint();
    void setRollbackOnly();
    boolean isRollbackOnly();
    void flush();
    boolean isCompleted();
}

事物攔截器:TransactionInterceptor.java

會攔截聲明@Transaction註解的方法和類,以及通過

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    public TransactionInterceptor() {
    }
    public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributes(attributes);
    }
    public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributeSource(tas);
    }

    public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
        });
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(this.getTransactionManagerBeanName());
        oos.writeObject(this.getTransactionManager());
        oos.writeObject(this.getTransactionAttributeSource());
        oos.writeObject(this.getBeanFactory());
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        this.setTransactionManagerBeanName((String)ois.readObject());
        this.setTransactionManager((PlatformTransactionManager)ois.readObject());
        this.setTransactionAttributeSource((TransactionAttributeSource)ois.readObject());
        this.setBeanFactory((BeanFactory)ois.readObject());
    }
}

事物的執行過程:

技術分享圖片

事物的四大特性ACID

1、原子性(Atomicity):事務開始後所有操作,要麽全部做完,要麽全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。  

2、一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。  

3、隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何幹擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。  

4、持久性(Durability):事務完成後,事務對數據庫的所有更新將被保存到數據庫,不能回滾。

事物的隔離級別

  1. RU:READ_UNCOMMITTED:未提交讀
    • 一個事物操作後回滾,導致另一事物讀取的數據和數據庫中的數據不一致。
  2. RC:READ_COMMITTED:提交讀
    • 一個事物操作後提交,導致另一個事物在前一次事物提交前和提交後讀取的數據不一致,不能防止重復讀。
  3. RR:REPEATABLE_READ:可重復讀:讀數據加悲觀鎖,例如 select ... form ... for update
  4. SERIALIZABLE:串行化:串行化,最高的事務隔離級別,不管多少事務,挨個運行完一個事務的所有子事務之後才可以執行另外一個事務裏面的所有子事務,這樣就解決了臟讀、不可重復讀和幻讀的問題了 。

技術分享圖片

事物的傳播行為

技術分享圖片

常用的傳播行為:

  1. REQUIRED:事物存在加入事物,事物不存在則創建一個事物。

  2. REQUIRED_NEW:事物不管是否存在,都創建一個新的事物,上層事物掛起。

  3. SUPPORTS:支持事物,但是有事物存在,才會加入到事物中,沒有事物存在不會創建事物,運行在無事物中。

  4. NOT_SUPPORTS:不支持事物,如果存在事物,當前事物被掛起。

參考:https://blog.csdn.net/weixin_39625809/article/details/80707695

避免 Spring 的 AOP 的自調用問題

在 Spring 的 AOP 代理下,只有目標方法由外部調用,目標方法才由 Spring 生成的代理對象來管理,這會造成自調用問題。若同一類中的其他沒有@Transactional 註解的方法內部調用有@Transactional 註解的方法,有@Transactional 註解的方法的事務被忽略,不會發生回滾。

解決方案:

<tx:annotation-driven mode="aspectj" /> <!-- 指定模式 -->
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
</bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect"
    factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager" />
</bean>

AnnotationDrivenBeanDefinitionParser的作用分析

public BeanDefinition parse(Element element, ParserContext parserContext) {
    registerTransactionalEventListenerFactory(parserContext);
    String mode = element.getAttribute("mode");
    if ("aspectj".equals(mode)) {//解決自調用問題
        // mode="aspectj"
        registerTransactionAspect(element, parserContext);
    }
    else {
        // 默認為proxy模式
        // 所以要執行該句
        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }
    return null;
}

AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    // 在5)中單獨分析該句代碼的功能
    AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
 
    // txAdvisorBeanName值為 org.springframework.transaction.config.internalTransactionAdvisor
    String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
    if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
        Object eleSource = parserContext.extractSource(element);
 
        // 1.註冊類AnnotationTransactionAttributeSource到Spring中
        RootBeanDefinition sourceDef = new RootBeanDefinition(
                "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
        sourceDef.setSource(eleSource);
        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
 
        // 2.註冊類TransactionInterceptor到Spring中
        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
        interceptorDef.setSource(eleSource);
        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registerTransactionManager(element, interceptorDef);
        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
 
        // 2.註冊類BeanFactoryTransactionAttributeSourceAdvisor到Spring中
        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);
    }
}

Spring的事物原理