七、Spring事务管理

49 阅读5分钟

一,Spring事务

事务作用:在数据层保障一系列的数据库操作同成功同失败 Spring事务作用:在数据层业务层保障一系列的数据库操作同成功同失败

Spring事务通过接口:

public interface PlatFormTransactionManager{
    void commit(TransactionStatus stauts) throws TransactionException;
    void rollback(TransactionStatus stauts) throws TransactionException;
}

它提供了一个最基础的实现类

public void DataSourceTransactionManager{
    
}

这个实现类内部用的是JDBC的事务,mybatis内部用的也是JDBC的事务。


快速入门:

  1. 业务层接口上添加Spring事务管理

    public interface AccountService{
        
        @Transactional
        public void transfer(String out,String in,Double money);
    }
    

    注意:

    • Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
    • 注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
  2. 注册事务管理器

    @Configuration
    public class JdbcConfig{
        @Bean
    	public PlatFormTransactionManager transactionManager(DataSource datasource){
        	DataSourceTransactionManager ptm=new DataSourceTransactionManager();
        	ptm.setDataSource(datasource);
    	}
    }
    

    事务管理器要根据实现技术进行选择,MyBatis框架使用的是JDBC事务,故我们SSM一般就是注册JDBC事务。

  3. 开启注解方式事务驱动

    @EnableTransactionManagement
    @Configuration
    public class SpringConfig {
    }
    

    如果是基于SpringBoot开发那么不需要操作2,3两步,直接添加注解即可

二,Spring事务角色

事务角色

  • 事务管理员发起事务方,在Spring中通常指代业务层开启事务的方法
  • 事务协调员加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法

默认情况下,我们业务层两个执行的方法属于两个单独的事务:

image-20240702110213067

在加入注解后:

image-20240702110258917

三,@Transactional注解

image-20231104171539797

image-20231104171634890

三,事务属性

3.1 事务的回滚

image-20231104171919926

3.2 事务的传播行为

image-20231104172238681

常见的事务传播行为:

image-20231104172348544

required:

  • 假设A有事务,则B就加入A的事务。
  • 假设A没有事务,则B就创建一个新的事务。
  • 大部分情况下都是用该传播行为即可。

requires_new:

  • 无论A有没有事务,B都会创建一个新的事务。

  • 当我们不希望事务之间相互影响时,可以使用该传播行为。

    比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。

supports:

  • 假A有事务,那么事务B就加入A的事务
  • 假设A没有事务,那么B也不存在事务

not_supported:

  • 假设A有事务,那么A会在执行B的时候挂起,等待b执行完毕再继续运行事务
  • 假设A没有事务,那么a,b在无事务的状态下执行。

3.3 事务的隔离级别

isolation 属性用于指定事务的隔离级别,它定义了一个事务与其他事务相互隔离的程度。隔离级别可以影响事务的并发性和一致性。不同的隔离级别会影响数据库在处理并发事务时的行为,从而决定事务是否会遇到**脏读(Dirty Read)、不可重复读(Non-repeatable Read)和幻读(Phantom Read)**等问题。

常见事务隔离级别

  1. Isolation.DEFAULT

    • 描述: 使用底层数据库的默认隔离级别。每个数据库管理系统(DBMS)都有自己的默认隔离级别,通常是 READ_COMMITTED

    • 适用场景: 当不确定应用程序具体需要哪种隔离级别时,或者希望使用数据库的默认行为。

  2. Isolation.READ_UNCOMMITTED

    • 描述: 允许一个事务读取另一个事务尚未提交的数据(脏读)。可能会出现脏读、不可重复读和幻读。
    • 适用场景: 在数据一致性要求不高但需要高并发性能的场景下使用。例如:临时统计分析。
  3. Isolation.READ_COMMITTED

    • 描述: 一个事务只能读取另一个事务已经提交的数据。避免了脏读,但可能会出现不可重复读和幻读。
    • 适用场景: 大多数应用程序,特别是需要避免脏读的场景。例如:大多数在线事务处理系统(OLTP)。
  4. Isolation.REPEATABLE_READ

    • 描述: 确保在同一个事务内多次读取同样的数据结果是一致的(避免不可重复读)。可能会出现幻读。
    • 适用场景: 需要在事务中多次读取相同数据且需要一致性的场景。例如:银行账户转账。
  5. Isolation.SERIALIZABLE

    • 描述: 提供严格的事务隔离,确保事务按顺序执行。避免脏读、不可重复读和幻读,但会导致性能显著下降,因而并发性最低。
    • 适用场景: 数据一致性要求极高且并发性要求较低的场景。例如:金融交易系统。

3.4 事务失效情况

  1. @Transactional 应用在非 public 修饰的方法上

  2. @Transactional 注解属性 propagation 设置错误

  3. @Transactional 注解属性 rollbackFor 设置错误

  4. 同一个类中方法调用,导致@Transactional失效

    开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但**方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。**这也是经常犯错误的一个地方。