【Spring】核心概念:事务

新博客:https://blog.bigdataboy.cn/article/453.html

什么是事务

事务是逻辑上的一组操作,主要是对数据库数据的操作,要么都执行,要么都不执行,重点是 ,所以当这组操作不一致时,那么就 自动进行回滚 ,把数据恢复这组操作之前,这样数据库的数据不会出错了

转账案例

事务这个概念最早是在 数据库 接触到,但是感觉并不明显,这里可以通过这个案例感受一下

a 给 b 转账 100

正常情况

  • a 的 余额 减少 100
  • b 的 余额 增加 100
public void transfer(String out, String in, Double money) {
    // 转账
    accountDao.inMoney(in, money);
    accountDao.outMoney(out, money);
}

如果在转账过程中出现异常,不使用事务的话,就会出现,一方钱减少了,而另一方确没有增加

public void transfer(String out, String in, Double money) {
    // 转账
    accountDao.inMoney(in, money);
    // 期间出现报错
    accountDao.outMoney(out, money);
}

Spring 事务处理

第一步、定义该函数需要事务处理,在接口上定义

项目使用的 DataSource 要一样,不然事务无法实现,案例中指 MyBatis 初始化 SqlSessionFactoryBean 时传入的 DataSource 和 JDBC 交给 Spring 的事务的 DataSource 一致

public interface AccountService {
    @Transactional  // 该注解 开启事务
    public void transfer(String out, String in, Double money);
}

第二步、在 JdbcConfig 类,定义 事务管理 Bean 交给 Spring 容器管理

@Configuration
public class JdbcConfig {

    @Value("${jdbc.driver}")
    public String driverClassName;

    @Value("${jdbc.url}")
    public String url;

    @Value("${jdbc.username}")
    public String username;

    @Value("${jdbc.password}")
    public String password;

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean  // 把事务管理器交给 Spring 管理
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource); 
        return transactionManager;

    }
}

第三步、在 SpringConfig 使用注解开启事务

@Configuration
@ComponentScan({"cn.bigdataboy"})
@PropertySource({"classpath:jdbc.properties"})
@Import({MyBatisConfig.class, JdbcConfig.class})
@EnableTransactionManagement  // 开启事务管理器
public class SpringConfig {
}

测试

注意 默认状态并不是所有的异常都会回滚,可以通过 事务属性 进行控制

mark

事务角色

在上述案例中, 小事务一 和 二 (事务协调员) 会被加入到 大的事务(事务管理员) ,由 事务管理员 统一管理

事务管理员:在 Spring 中通常指 开启事务的方法

事务协调员:在 Spring 中通常指 数据层方法,也可以是业务层方法

mark

事务的属性

事务的属性能使 事务管理员事务协调员 精细化的管理

属性 作用 实例
readOnly 设置是否为只读事务 readOnly=true 只读事务
timeout 设置事务超时时间 timeout = -1 (永不超时)
rollbackFor 设置事务回滚异常(class) rollbackFor = {NullPointerException.class}
rollbackForClassName 设置事务回滚异常(String) 同上,只是参数为字符串
noRollbackFor 设置事务不回滚异常(class) noRollbackFor = {NullPointerException.class}
noRollbackForClassName 设置事务不回滚异常(String) 同上,只是参数为字符串
propagation 事务传播 见下面

mark

事务传播

默认情况下,发送错误时,子事务全部都要回滚,那有一些事务是不需要回滚(记录日志到数据库),这也是需要实现的,子事务可以控制自己是否需要主事务控制。

mark

public interface AccountLogService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)  // 该注解 开启事务
    public void add(String out, String in, Double money);
}

propagation 参数说明

T 代表事务)
传播属性
事务管理员 事务协调员
REQUIRED(默认) 开启 T / 无 加入 T / 新建 T2
REQUIRES_NEW 开启 T / 无 新建 T2 / 新建 T2
SUPPORTS 开启 T / 无 加入 T / 无
NOT_SUPPORTED 开启 T / 无 无 / 无
MANDATORY 开启 T / 无 加入 T / ERROR
NEVER 开启 T / 无 ERROT / 无
NESTED 开启 T / 无 设置 savePoint,一但事务回滚,事务将回滚到 savaPoint 处,交由客户端提交/回滚

案例代码:https://pan.bigdataboy.cn/s/QgVFn

发表评论 / Comment

用心评论~