Spring 事务传播行为

  • 官方文档 中介绍了三种传播行为:PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED,实际上Spring的事务传播行为共有七种,Spring源码 TransactionDefinition.java 中描述了这七种传播行为。

      public interface TransactionDefinition {
    
          /**
          * Support a current transaction; create a new one if none exists.
          * Analogous to the EJB transaction attribute of the same name.
          * <p>This is typically the default setting of a transaction definition,
          * and typically defines a transaction synchronization scope.
          */
          int PROPAGATION_REQUIRED = 0;
    
          /**
          * Support a current transaction; execute non-transactionally if none exists.
          * Analogous to the EJB transaction attribute of the same name.
          * <p><b>NOTE:</b> For transaction managers with transaction synchronization,
          * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
          * at all, as it defines a transaction scope that synchronization might apply to.
          * As a consequence, the same resources (a JDBC {@code Connection}, a
          * Hibernate {@code Session}, etc) will be shared for the entire specified
          * scope. Note that the exact behavior depends on the actual synchronization
          * configuration of the transaction manager!
          * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
          * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
          * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
          * synchronization conflicts at runtime). If such nesting is unavoidable, make sure
          * to configure your transaction manager appropriately (typically switching to
          * "synchronization on actual transaction").
          * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
          * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
          */
          int PROPAGATION_SUPPORTS = 1;
    
          /**
          * Support a current transaction; throw an exception if no current transaction
          * exists. Analogous to the EJB transaction attribute of the same name.
          * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
          * scope will always be driven by the surrounding transaction.
          */
          int PROPAGATION_MANDATORY = 2;
    
          /**
          * Create a new transaction, suspending the current transaction if one exists.
          * Analogous to the EJB transaction attribute of the same name.
          * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
          * on all transaction managers. This in particular applies to
          * {@link org.springframework.transaction.jta.JtaTransactionManager},
          * which requires the {@code javax.transaction.TransactionManager} to be
          * made available it to it (which is server-specific in standard Java EE).
          * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
          * transaction synchronizations. Existing synchronizations will be suspended
          * and resumed appropriately.
          * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
          */
          int PROPAGATION_REQUIRES_NEW = 3;
    
          /**
          * Do not support a current transaction; rather always execute non-transactionally.
          * Analogous to the EJB transaction attribute of the same name.
          * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
          * on all transaction managers. This in particular applies to
          * {@link org.springframework.transaction.jta.JtaTransactionManager},
          * which requires the {@code javax.transaction.TransactionManager} to be
          * made available it to it (which is server-specific in standard Java EE).
          * <p>Note that transaction synchronization is <i>not</i> available within a
          * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
          * will be suspended and resumed appropriately.
          * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
          */
          int PROPAGATION_NOT_SUPPORTED = 4;
    
          /**
          * Do not support a current transaction; throw an exception if a current transaction
          * exists. Analogous to the EJB transaction attribute of the same name.
          * <p>Note that transaction synchronization is <i>not</i> available within a
          * {@code PROPAGATION_NEVER} scope.
          */
          int PROPAGATION_NEVER = 5;
    
          /**
          * Execute within a nested transaction if a current transaction exists,
          * behave like {@link #PROPAGATION_REQUIRED} otherwise. There is no
          * analogous feature in EJB.
          * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
          * specific transaction managers. Out of the box, this only applies to the JDBC
          * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
          * when working on a JDBC 3.0 driver. Some JTA providers might support
          * nested transactions as well.
          * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
          */
          int PROPAGATION_NESTED = 6;
          // ...	
      }
    

总结为:

传播行为 描述
PROPAGATION_REQUIRED 0 若当前存在事务则沿用,否则新建事务
PROPAGATION_SUPPORTS 1 若当前存在事务则沿用,否则以非事务的方式执行
PROPAGATION_MANDATORY 2 若当前存在事务则沿用,否则报错
PROPAGATION_REQUIRES_NEW 3 创建新事务,若当前存在事务则将其挂起
PROPAGATION_NOT_SUPPORTED 4 以非事务的方式执行,若当前存在事务则将其挂起
PROPAGATION_NEVER 5 不支持事务,若当前存在事务则报错
PROPAGATION_NESTED 6 若当前存在事务则沿用,否则新建事务
  • PROPAGATION_REQUIREDPROPAGATION_NESTED 不同在于,假设存在事务A中嵌套了事务B,当事务B执行出错时,REQUIRED 会将整个事务(包含A、B)进行回滚,而 NESTED 只会回滚事务B。

Spring 事务隔离级别

  • Spring源码 TransactionDefinition.java 中描述了Spring的事务隔离级别

      public interface TransactionDefinition {
          // ...
          /**
          * Use the default isolation level of the underlying datastore.
          * All other levels correspond to the JDBC isolation levels.
          * @see java.sql.Connection
          */
          int ISOLATION_DEFAULT = -1;
    
          /**
          * Indicates that dirty reads, non-repeatable reads and phantom reads
          * can occur.
          * <p>This level allows a row changed by one transaction to be read by another
          * transaction before any changes in that row have been committed (a "dirty read").
          * If any of the changes are rolled back, the second transaction will have
          * retrieved an invalid row.
          * @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
          */
          int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
    
          /**
          * Indicates that dirty reads are prevented; non-repeatable reads and
          * phantom reads can occur.
          * <p>This level only prohibits a transaction from reading a row
          * with uncommitted changes in it.
          * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
          */
          int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
    
          /**
          * Indicates that dirty reads and non-repeatable reads are prevented;
          * phantom reads can occur.
          * <p>This level prohibits a transaction from reading a row with uncommitted changes
          * in it, and it also prohibits the situation where one transaction reads a row,
          * a second transaction alters the row, and the first transaction re-reads the row,
          * getting different values the second time (a "non-repeatable read").
          * @see java.sql.Connection#TRANSACTION_REPEATABLE_READ
          */
          int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
    
          /**
          * Indicates that dirty reads, non-repeatable reads and phantom reads
          * are prevented.
          * <p>This level includes the prohibitions in {@link #ISOLATION_REPEATABLE_READ}
          * and further prohibits the situation where one transaction reads all rows that
          * satisfy a {@code WHERE} condition, a second transaction inserts a row
          * that satisfies that {@code WHERE} condition, and the first transaction
          * re-reads for the same condition, retrieving the additional "phantom" row
          * in the second read.
          * @see java.sql.Connection#TRANSACTION_SERIALIZABLE
          */
          int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;
          // ...
      }
    

总结为:

隔离级别 描述
ISOLATION_DEFAULT -1 使用底层数据库的隔离级别
ISOLATION_READ_UNCOMMITTED 1 可能出现脏读不可重复读幻读
ISOLATION_READ_COMMITTED 2 不会出现脏读,可能出现不可重复读幻读
ISOLATION_REPEATABLE_READ 4 不会出现脏读不可重复读,可能出现幻读
ISOLATION_SERIALIZABLE 8 不会出现脏读不可重复读幻读

Spring 事务的默认配置

  • Spring源码DefaultTransactionDefinition.java中定义了Spring事务的默认配置:

      public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
          //...
          private int propagationBehavior = PROPAGATION_REQUIRED;
    
          private int isolationLevel = ISOLATION_DEFAULT;
          // ...
      }
    
  • 由上可知,Spring事务默认传播行为PROPAGATION_REQUIRED,默认隔离级别为使用底层数据库的隔离级别。