Skip to content

[TOC]

前言 ​

学习目标 ​

  1. 理解Spring事务核心思想
  2. 熟悉Spring事务的注解@Transactional

前置知识准备 ​

  • 事务
  • AOP思想

事务的回顾 ​

事务的特性 ​

  • 原子性 Atomicity
  • 一致性 Consistency
  • 隔离性 Isolation
  • 持久性 Durability

事务并发引起的问题 ​

  • 脏读
    • 一个事务读取到另外一个事务的数据
  • 不可重复读
    • 一个事务读取到另外一个事务的数据
  • 虚读/幻读
    • 一个事务读取到另外一个事务的数据

数据库的隔离级别 ​

  • 读未提交(Read uncommitted)
  • 读已提交(Read committed)
  • 可重复读(Repeatable read)
  • 串行化(Serializable)
脏读不可重复读虚读/幻读
读未提交×××
读已提交√××
可重复读√√×
串行化√√√

MySql的默认隔离级别是可重复读,但没有虚读问题的。

事务的核心接口 ​

  • PlatformTransactionManager 平台事务管理器
  • TransactionStatus 事务状态
  • TransactionDefinition 事务定义

PlatformTransactionManager平台事务管理器 ​

平台事务管理器,Spring要管理事务,必须使用事务管理器 有多种实现,通过实现此接口,Spring可以管理任何实现了这些接口的事务。 开发人员可以使用统一的编程模型来控制管理事务。

常见的事务管理器的实现 DataSourceTransactionManager,jdbc开发时事务管理器,使用JdbcTemplate、MyBatis HibernateTransactionManager,Hibernate开发时事务管理器,整合Hibernate

java
public interface PlatformTransactionManager extends TransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

TransactionStatus事务状态 ​

获取事务的状态(回滚点、是否完成、是否新事务、是否回滚)属性,是一个过程值

java
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
  boolean hasSavepoint();

  void flush();
}

提供了关于事务状态的方法

TransactionDefinition事务定义 ​

定义事务的名称、隔离级别、传播行为、超时时间长短、只读属性等

java
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;

  default int getPropagationBehavior() {
    return 0;
  }

  default int getIsolationLevel() {
    return -1;
  }

  default int getTimeout() {
    return -1;
  }

  default boolean isReadOnly() {
    return false;
  }

  @Nullable
  default String getName() {
    return null;
  }

  static TransactionDefinition withDefaults() {
    return StaticTransactionDefinition.INSTANCE;
  }
}

事务的传播行为 ​

事务的传播行为属于TransactionDefinition,这个概念是之前没有讲过的一个概念

指多个方法之间如何来共享事务

  • REQUIRED
    • 一荣俱荣
  • REQUIRES_NEW
    • 自私型
  • NESTED
    • 无私型

REQUIRED ​

如果当前没有事务,就新建一个事务; 如果当前存在,则加入进来,作为一个事务。

一荣俱荣,一损俱损。要么一起提交,要么一起回滚。

现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?

REQUIRES_NEW ​

如果当前没有事务,新建事务; 如果当前存在事务,则新建一个事务。

自私型。外部不会影响内部,内部会影响外围。

现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?

NESTED ​

如果当前没有事务,就新建一个事务; 如果当前存在事务,则以嵌套事务的方式运行。

无私型。外围会影响内部,内部不会影响外围。

现在有两个method,methodB(外围)调用了methodA(内部)
Q1:如果methodB发生异常,谁回滚?
Q2:如果methodA发生异常,谁回滚?

其他传播行为 ​

传播行为描述
PROPAGATION_SUPPORTS支持当前事务,假设当前没有事务,就以非事务方式运行
PROPAGATION_MANDATORY支持当前事务,假设当前没有事务,就抛出异常
PROPAGATION_NOT_SUPPORTED以非事务方式运行操作。假设当前存在事务,就把当前事务挂起
PROPAGATION_NEVER以非事务方式运行,假设当前存在事务,则抛出异常

事务的案例 ​

不管使用的是哪一个案例,只要使用Spring事务,必然要使用Spring事务管理器。

java
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
  DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
  transactionManager.setDataSource(dataSource);
  return transactionManager;
}

TransactionTemplate ​

事务的模板,采用事务模板提供的方法来使用事务

在容器中注册TransactionTemplate组件

java
@Configuration
@ComponentScan("com.cskaoyan")
public class MyBatisConfiguration {

    // javaConfig讲过这个组件注册
    // MyBatis注册的组件略

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(transactionManager);
        return transactionTemplate;
    }
}

使用TransactionTemplate提供的方法

java
@Service
public class AccountServiceImpl implements AccountService{
    @Autowired
    AccountDao accountDao;
    @Autowired
    TransactionTemplate transactionTemplate;
    @Override
    public void transfer(String from, String dest, Integer money) {
        Integer fromMoney = accountDao.selectMoneyByName(from) - money;
        Integer destMoney = accountDao.selectMoneyByName(dest) + money;

        //execute方法的返回值 是doInTransaction方法的返回值
        Integer execute = transactionTemplate.execute(new TransactionCallback<Integer>() {
            //需要增加事务的代码放入到doInTransaction中
            //如果需要增加事务的方法需要返回值 → 直接返回对应的值即可
            @Override
            public Integer doInTransaction(TransactionStatus transactionStatus) {

                accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
                int i = 1/0;
                accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务
                return null;
            }
        });
        /*transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
                accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务
            }
        });*/
    }
}

Transactional注解 &#8203;

@Transactional注解的ElementType为,意味着可以写在

java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

使用注解前,需要

java
@Configuration
@ComponentScan("com.cskaoyan")
@EnableTransactionManagement
public class MyBatisConfiguration {}

直接使用@Transactional注解,可以使用注解提供的属性

java
/**
 * 在类上增加@Transactional 意味着该类下的所有方法都增加事务
 * @Transactional要增加在容器中的组件或组件中的方法里
 */
@Transactional
@Service
public class AccountServiceImpl implements AccountService{
    @Autowired
    AccountDao accountDao;

    //对应的方法增加上事务
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = 5)
    @Override
    public void transfer(String from, String dest, Integer money) {
        Integer fromMoney = accountDao.selectMoneyByName(from) - money;
        Integer destMoney = accountDao.selectMoneyByName(dest) + money;

        accountDao.updateMoneyByName(from, fromMoney);//操作了数据库中的数据,需要增加事务
        int i = 1/0;
        accountDao.updateMoneyByName(dest, destMoney);//操作了数据库中的数据,需要增加事务

    }
}

笔记 &#8203;

  • spring-jdbc依赖。spring管理事务
  • InitializingBean初始化生命周期
  • 整合MyBatice框架是为了把框架需要的实例放到容器里管理起来
  • 事务定义,超时时间5,说明5s后就不能提交了
  • Requires_New,内部方法更重要,Nested外部方法更重要。比如register调用coupon,用nested,register失败则coupon也回滚,反之则coupon回滚,register不变。
  • 管理事务实际上是在管理连接,连接在连接池