内容简介:前面介绍的几篇事务的博文,主要是利用本文将介绍另外一种事务的使用姿势,借助本篇主要介绍的是
前面介绍的几篇事务的博文,主要是利用 @Transactional 注解的声明式使用姿势,其好处在于使用简单,侵入性低,可辨识性高(一看就知道使用了事务);然而缺点也比较明显,不够灵活,稍不注意,可能就因为姿势不对,导致事务不生效
本文将介绍另外一种事务的使用姿势,借助 TransactionTemplate 的编程式事务
I. 配置
本篇主要介绍的是 jdbcTemplate + transactionTemplate 来完成一个编程式事务的实例demo
创建一个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相关的信息
```properties
## 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. 使用说明
1. 初始化
创建几条数据,用于事务操作
@Service
public class ManualDemo {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private JdbcTemplate jdbcTemplate;
@PostConstruct
public void init() {
String sql = "replace into money (id, name, money) values (220, '初始化', 200)";
jdbcTemplate.execute(sql);
}
}
2. 使用case
为了演示事务的特性,我们设计几个简单的 sql 操作,并抛出异常,引发回滚,如下
- 在doUpdate方法中,显示更新name,输出更新的结果,然后再更新money的值,最后抛出一个异常,希望事务回滚
private boolean doUpdate(int id) throws Exception {
if (this.updateName(id)) {
this.query("after updateMoney name", id);
if (this.updateMoney(id)) {
return true;
}
}
throw new Exception("参数异常");
}
private boolean updateName(int id) {
String sql = "update money set `name`='更新' where id=" + id;
jdbcTemplate.execute(sql);
return true;
}
public void query(String tag, int id) {
String sql = "select * from money where id=" + id;
Map map = jdbcTemplate.queryForMap(sql);
System.out.println(tag + " >>>> " + map);
}
private boolean updateMoney(int id) {
String sql = "update money set `money`= `money` + 10 where id=" + id;
jdbcTemplate.execute(sql);
return false;
}
上面这一端逻辑,如果看了前面几篇博文,会比较熟悉,区别在于doUpdate方法上面没有添加 @Transactional 注解,当下它的调用并不会在事务中执行
接下来我们看一下编程式事务的核心写法
public void testTransaction(int id) {
transactionTemplate.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus transactionStatus) {
try {
return doUpdate(id);
} catch (Exception e) {
transactionStatus.setRollbackOnly();
return false;
}
}
});
}
如上,将方法的调用,封装在 transactionTemplate.execute 的调用中,通过设置 transactionStatus.setRollbackOnly() 来标记回滚
通过前面几篇博文的学习我们知道实际使用时,事务的隔离级别,传递属性也很重要,在编程式事务中,当然也是可以设置的
// 设置隔离级别 transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT); // 设置传播属性 transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
最后写一个测试代码,验证一下是否生效
@Component
public class TransactionalSample {
@Autowired
private ManualDemo manualDemo;
public void testManualCase() {
System.out.println("======= 编程式事务 start ========== ");
manualDemo.query("transaction before", 220);
manualDemo.testTransaction(220);
manualDemo.query("transaction end", 220);
System.out.println("======= 编程式事务 end ========== ");
}
}
输出结果如下,最终数据big没有被修改
======= 编程式事务 start ==========
transaction before >>>> {id=220, name=初始化, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
after updateMoney name >>>> {id=220, name=更新, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
transaction end >>>> {id=220, name=初始化, money=200, is_deleted=false, create_at=2020-02-03 13:52:39.0, update_at=2020-02-03 13:52:39.0}
======= 编程式事务 end ==========
III. 其他
0. 系列博文&源码
系列博文
- 180926-SpringBoot高级篇DB之基本使用
- 190407-SpringBoot高级篇JdbcTemplate之数据插入使用姿势详解
- 190412-SpringBoot高级篇JdbcTemplate之数据查询上篇
- 190417-SpringBoot高级篇JdbcTemplate之数据查询下篇
- 190418-SpringBoot高级篇JdbcTemplate之数据更新与删除
- 200119-SpringBoot系列教程之声明式事务Transactional
- 200120-SpringBoot系列教程之事务隔离级别知识点小结
- 200202-SpringBoot系列教程之事务传递属性
- 200203-SpringBoot系列教程之事务不生效的几种case
源码
- 工程: https://github.com/liuyueyi/spring-boot-demo
- 实例源码: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/101-jdbctemplate-transaction
1. 一灰灰Blog
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
- 一灰灰Blog个人博客 https://blog.hhui.top
- 一灰灰Blog-Spring专题博客 http://spring.hhui.top
打赏 如果觉得我的文章对您有帮助,请随意打赏。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 佈署 Angular 應用程式至 IIS 虛擬目錄 / 應用程式
- 佈署 Angular 應用程式至 IIS 虛擬目錄 / 應用程式
- matlab—方程式求根
- 八、Golang过程式编程
- 如何降低程式碼複雜度 ?
- 算法系列(1):Google方程式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
An Introduction to the Analysis of Algorithms
Robert Sedgewick、Philippe Flajolet / Addison-Wesley Professional / 1995-12-10 / CAD 67.99
This book is a thorough overview of the primary techniques and models used in the mathematical analysis of algorithms. The first half of the book draws upon classical mathematical material from discre......一起来看看 《An Introduction to the Analysis of Algorithms》 这本书的介绍吧!