Spring TX 使用及事务属性

@Transactional 的使用

这个事务注解可以用在类上,也可以用在方法上:

  • 事务注解标记到服务组件类级别,相当于为该服务组件的每个服务方法都应用了这个注解
  • 事务注解应用在方法级别,是更细粒度的一种事务注解方式
  • 如果某个方法和该方法所属类上都有事务注解属性,优先使用方法上的事务注解属性

另外,Spring 支持三个不同的事务注解:

  • Spring 事务注解 org.springframework.transaction.annotation.Transactional(官方推荐)
  • JTA 事务注解 javax.transaction.Transactional
  • EJB 3 事务注解 javax.ejb.TransactionAttribute

@Transactional 注解参数

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    /**
     * value 和 transactionManager 属性是一样的意思。当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器
     */
    @AliasFor("transactionManager")
    String value() default "";
    @AliasFor("value")
    String transactionManager() default "";

    /**
     * 事务的传播行为
     */
    Propagation propagation() default Propagation.REQUIRED;

    /**
     * 事务的隔离级别
     */
    Isolation isolation() default Isolation.DEFAULT;

    /**
     * 事务的超时时间,默认为 -1
     */
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

    /**
     * 是否只读,默认 false
     */
    boolean readOnly() default false;

    /**
     * 需要回滚的异常,可以指定多个异常类型,不指定默认只回滚 RuntimeException 和 Error
     */
    Class<? extends Throwable>[] rollbackFor() default {};
    String[] rollbackForClassName() default {};

    /**
     * 不需要回滚的异常
     */
    Class<? extends Throwable>[] noRollbackFor() default {};
    String[] noRollbackForClassName() default {};
}

Spring 会将事务提交切换到手动模式

public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
    @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();

            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); // 取消自动提交
            }

            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) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, obtainDataSource());
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

事务配置 TransactionDefinition

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法得到事务,这个方法里面的参数是 TransactionDefinition,这个类就定义了一些基本的事务属性。

事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了 5 个方面:

在这里插入图片描述

常用实现类为:DefaultTransactionDefinition,TransactionAttribute 接口也继承自此接口

public interface TransactionDefinition {
    // 7 种类型的事务传播行为,如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作
    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; // 如果当前存在事务,则在嵌套事务(它是一个子事务,但它仍还是外部事务的一部分,外部事务提交了它才提交)内执行


    // 4 种:隔离级别
    // PlatformTransactionManager 的默认隔离级别(对大多数数据库来说就是 ISOLATION_ READ_COMMITTED
    // MySQL 默认采用 ISOLATION_REPEATABLE_READ,Oracle 默认采用 READ__COMMITTED
    int ISOLATION_DEFAULT = -1;
    // 读未提交,最低的隔离级别。可能导致脏、幻读、不可重复读
    int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
    // 读已提交,大多数数据库的默认级别。可防止脏读,但幻读、不可重复读仍可能发生
    int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
    // 可重复读。该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其它事务修改了所查询的数据
    // 可防止脏读,不可重复读,但幻读仍可能发生
    int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
    // 序列化。代价最大、可靠性最高的隔离级别,所有的事务都是按顺序一个接一个地执行。避免所有不安全读取
    int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;


    // 默认的超时时间,-1 表示不超时(单位是秒)
    // 如果超过该时间限制,但事务还没有完成,则自动回滚事务
    int TIMEOUT_DEFAULT = -1;

    /**
     * 返回事务的传播行为(一共7种)
     */
    default int getPropagationBehavior() {
        return PROPAGATION_REQUIRED;
    }

    /**
     * 返回事务的隔离级别。事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
     */
    default int getIsolationLevel() {
        return ISOLATION_DEFAULT;
    }

    /**
     * 返回超时时间(事务必须在多少秒内完成)
     */
    default int getTimeout() {
        return TIMEOUT_DEFAULT;
    }

    /**
     * 事务是否只读(事务管理器能够根据这个返回值进行优化,确保事务是只读的)
     */
    default boolean isReadOnly() {
        return false;
    }

    /**
     * 事务的名字,可以为 null
     */
    @Nullable
    default String getName() {
        return null;
    }

    /**
     * 静态构建方法
     * 返回带有默认值且不可修改的 TransactionDefinition
     */
    static TransactionDefinition withDefaults() {
        return StaticTransactionDefinition.INSTANCE;
    }
}

事务四大特性:ACID

  • Atomicity(原子性):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用
  • Consistency(一致性):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏
  • Isolation(隔离性):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
  • Durability(持久性):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中

CAP:Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)

BASE 理论:Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写

事务不生效的原因

确保业务和事务入口在同一个线程里,否则事务是不生效的

@Transactional 开启的事务 ,或者是基于接口的,或者是基于类的,代理被创建。所以在同一个类中一个无事务的方法调用另一个有事务的方法,事务是不会起作用的


https://blog.csdn.net/f641385712/article/details/89602418

https://blog.csdn.net/f641385712/article/details/80445933

https://blog.csdn.net/f641385712/article/details/80445912

https://www.cnblogs.com/jhxxb/p/10450944.html

原文地址:https://www.cnblogs.com/jhxxb/p/14137581.html