Spring事务分析

Spring事务最佳实践:

1. Spring事务不要用@Transaction(PS:如果用的话最好加到service层的方法上面而不要加到dao层、Controller层),会有一些情况导致事务回滚失败。

2. 最好使用代码来实现事务管理

3. 不要在事务里面执行RPC、HTTP请求等操作,避免由于网络抖动导致出现耗时事务的问题,耗时事务会长时间锁数据库.

   如果避免不了那么这就是一个分布式事务的问题了。

事务的传播性:

1.REQUIRED:方法在一个事务中执行,如果调用的方法已经在一个事务中,则使用该事务,否则将创建一个新的事务。(默认的)

2.MANDATORY:方法必须在一个事务中执行,也就是说调用的方法必须已经有一个事务,否则新抛出一个错误(ERROR)。

3.REQUIRESNEW:方法将在一个新的事务中执行,如果调用的方法已经在一个事务中,则暂停旧的事务。

4.SUPPORTS:如果方法在一个事务中被调用,则使用该事务,否则不使用事务。

5.NOT_SUPPORTED:如果方法在一个事务中被调用,将抛出一个错误(ERROR)

事务的实现原理:

使用编程式事务代码如下:

PlatformTransactionManager platformTransactionManager=new DataSourceTransactionManager();
        TransactionTemplate transactionTemplate=new TransactionTemplate();
        //设置事务的超时时间
        transactionTemplate.setTimeout(5000);
        //事务的隔离级别
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        //事务的传播行为
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //是否为只读事务
        transactionTemplate.setReadOnly(false);
        //获取事务
        TransactionStatus transactionStatus=platformTransactionManager.getTransaction(transactionTemplate);
        try{
            //数据库操作...
            //提交事务
            platformTransactionManager.commit(transactionStatus);
        }catch (Exception ex){
            //回滚事务
            platformTransactionManager.rollback(transactionStatus);
        }

这里我们先分析getTransaction方法:

@Override
    public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
            throws TransactionException {

        // Use defaults if no transaction definition given.
        TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
        //获取事务信息DataSourceTransactionObject,这里面主要包含事务的保存点,和连接上下文
        Object transaction = doGetTransaction();
        boolean debugEnabled = logger.isDebugEnabled();
        //判断当前线程的连接是否开启了事务txObject.getConnectionHolder().isTransactionActive()
        if (isExistingTransaction(transaction)) {
            //根据事务的传播性是否要开启新事务
            return handleExistingTransaction(def, transaction, debugEnabled);
        }
        //事务的超时时间不能少于默认的
        if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
        }

        // No existing transaction found -> check propagation behavior to find out how to proceed.
        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 {
                boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                DefaultTransactionStatus status = newTransactionStatus(
                        def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                //这里开始事务
                doBegin(transaction, def);
      //绑定事务相关信息到当前线程
                prepareSynchronization(status, def);
                return status;
            }
            catch (RuntimeException | Error ex) {
                resume(null, suspendedResources);
                throw ex;
            }
        }
        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);
        }
    }

 

我们真正分析doBegin方法,其他大部分逻辑是处理事务的传播性

@Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            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();
            //初始化事务
            //1、设置是否只读:con.setReadOnly(true);
            //2、设置隔离级别:con.setTransactionIsolation(definition.getIsolationLevel());
            Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);
            txObject.setReadOnly(definition.isReadOnly());
            //设置为手动提交事务
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false);
            }
            //发送事务只读指令 stmt.executeUpdate("SET TRANSACTION READ ONLY");
            prepareTransactionalConnection(con, definition);
            //设置当前连接的事务为激活状态,作为后面判断是否存在事务的标识
            txObject.getConnectionHolder().setTransactionActive(true);

            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            // 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);
        }
    }
posted @ 2020-01-08 10:36  myTang  阅读(198)  评论(0)    收藏  举报