SpringBoot系列教程之事务传递属性

SpringBoot系列教程之事务传递属性

200202-SpringBoot系列教程事务传递属性

对于mysql而言,关于事务的主要知识点可能几种在隔离级别上;在Spring体系中,使用事务的时候,还有一个知识点事务的传递属性同样重要,本文将主要介绍7中传递属性的使用场景

I. 配置

本文的case,将使用声明式事务,首先我们创建一个SpringBoot项目,版本为2.2.1.RELEASE,使用mysql作为目标数据库,存储引擎选择Innodb,事务隔离级别为RR

1. 项目配置

在项目pom.xml文件中,加上spring-boot-starter-jdbc,会注入一个DataSourceTransactionManager的bean,提供了事务支持

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> 2. 数据库配置

进入spring配置文件application.properties,设置一下db相关的信息

## DataSource spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password= 3. 数据库

新建一个简单的表结构,用于测试

CREATE TABLE `money` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名', `money` int(26) NOT NULL DEFAULT '0' COMMENT '钱', `is_deleted` tinyint(1) NOT NULL DEFAULT '0', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4; II. 使用说明 0. 准备

在正式开始之前,得先准备一些基础数据

@Component public class PropagationDemo { @Autowired private JdbcTemplate jdbcTemplate; @PostConstruct public void init() { String sql = "replace into money (id, name, money) values (420, '初始化', 200)," + "(430, '初始化', 200)," + "(440, '初始化', 200)," + "(450, '初始化', 200)," + "(460, '初始化', 200)," + "(470, '初始化', 200)," + "(480, '初始化', 200)," + "(490, '初始化', 200)"; jdbcTemplate.execute(sql); } }

其次测试事务的使用,我们需要额外创建一个测试类,后面的测试case都放在类PropagationSample中; 为了使输出结果更加友好,提供了一个封装的call方法

@Component public class PropagationSample { @Autowired private PropagationDemo propagationDemo; private void call(String tag, int id, CallFunc<Integer> func) { System.out.println("============ " + tag + " start ========== "); propagationDemo.query(tag, id); try { func.apply(id); } catch (Exception e) { System.out.println(e.getMessage()); } propagationDemo.query(tag, id); System.out.println("============ " + tag + " end ========== \n"); } @FunctionalInterface public interface CallFunc<T> { void apply(T t) throws Exception; } } 1. REQUIRED

也是默认的传递属性,其特点在于

如果存在一个事务,则在当前事务中运行

如果没有事务则开启一个新的事务

使用方式也比较简单,不设置@Transactional注解的propagation属性,或者设置为 REQUIRED即可

/** * 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务 * * @param id */ @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void required(int id) throws Exception { if (this.updateName(id)) { this.query("required: after updateMoney name", id); if (this.updateMoney(id)) { return; } } throw new Exception("事务回滚!!!"); }

上面就是一个基础的使用姿势

private void testRequired() { int id = 420; call("Required事务运行", id, propagationDemo::required); }

输出结果如下

============ Required事务运行 start ========== Required事务运行 >>>> {id=420, name=初始化, money=200, is_deleted=false, create_at=2020-02-02 15:23:26.0, update_at=2020-02-02 15:23:26.0} required: after updateMoney name >>>> {id=420, name=更新, money=200, is_deleted=false, create_at=2020-02-02 15:23:26.0, update_at=2020-02-02 15:23:46.0} 事务回滚!!! Required事务运行 >>>> {id=420, name=初始化, money=200, is_deleted=false, create_at=2020-02-02 15:23:26.0, update_at=2020-02-02 15:23:26.0} ============ Required事务运行 end ========== 2. SUPPORTS

其特点是在事务里面,就事务执行;否则就非事务执行,即

如果存在一个事务,支持当前事务

如果没有事务,则非事务的执行

使用姿势和前面基本一致

@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class) public void support(int id) throws Exception { if (this.updateName(id)) { this.query("support: after updateMoney name", id); if (this.updateMoney(id)) { return; } } throw new Exception("事务回滚!!!"); }

这个传递属性比较特别,所以我们的测试case需要两个,一个事务调用,一个非事务调用

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjdfj.html