序言:此前,我们主要通过XML配置Spring来托管事务。在SpringBoot则非常简单,只需在业务层添加事务注解(@Transactional )即可快速开启事务。虽然事务很简单,但对于数据方面是需要谨慎对待的,识别常见坑点对我们开发有帮助。

1. 引入依赖

<!--依赖管理 -->
<dependencies>
<dependency> <!--添加Web依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency> <!--添加Mybatis依赖 -->
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency><!--添加MySQL驱动依赖 -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency><!--添加Test依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2. 添加配置

主要是配置数据源和开启Mybatis的自动驼峰映射

@SpringBootApplication
public class MybatisTransactionApplication { public static void main(String[] args) {
//1.初始化
SpringApplication application= new SpringApplication(MybatisTransactionApplication.class); //2.添加数据源
Map<String,Object> map = new HashMap<>();
map.put("spring.datasource.url","jdbc:mysql://localhost:3306/socks?useSSL=false");
map.put("spring.datasource.username","root");
map.put("spring.datasource.password","root"); //3.开启驼峰映射 (Such as account_id ==> accountId)
map.put("mybatis.configuration.map-underscore-to-camel-case",true);
application.setDefaultProperties(map); //4.启动应用
application.run(args);
}
}

3. 添加数据库记录

打开 Navicat 的查询窗口,然后执行以下SQL:

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`account_id` varchar(30) ,
`account_name` varchar(30),
`balance` decimal(20,2),
PRIMARY KEY (`account_id`)
); insert into account values ('1','admin','1000.25');

执行完毕后,可以查询到账户数据,如图:

 
 

4. 编写代码

以操作账户金额为例,模拟正常操作金额提交事务,以及发生异常回滚事务。

其中控制层代码如下:

package com.hehe.controller;

@RestController
public class AccountController { @SuppressWarnings("all")
@Autowired
AccountService accountService; @GetMapping("/")
public Account getAccount() {
//查询账户
return accountService.getAccount();
} @GetMapping("/add")
public Object addMoney() {
try {
accountService.addMoney();
} catch (Exception e) {
return "发生异常了:" + accountService.getAccount();
}
return getAccount();
}
}

在业务层使用 @Transactional 开启事务,执行数据库操作后抛出异常。具体代码如下:

package com.hehe.service;

@Service
public class AccountService { @SuppressWarnings("all")
@Autowired
AccountMapper accountMapper; public Account getAccount() {
return accountMapper.getAccount();
} @Transactional
public void addMoney() throws Exception {
//先增加余额
accountMapper.addMoney();
//然后遇到故障
throw new RuntimeException("发生异常了..");
}
}

数据库层就很简单了,我们通过注解来实现账户数据的查询,具体如下:

package com.hehe.mapper;

@Mapper
public interface AccountMapper { @Select("select * from account where account_id=1")
Account getAccount(); @Update("update account set balance = balance+100 where account_id=1")
void addMoney();
}

其中 Account 实体对象如下:

package com.hehe.pojo;

public class Account {

    private String accountId;
private String accountName;
private BigDecimal balance; // Override toString Method ..
// Getter & Setters ..
}

5. 测试事务

启动应用,访问 http://localhost:8080 ,可以看到账户数据,如下:

 
 

然后访问 http://localhost:8080/add ,可以看到账户余额并没有增加,如下: 也就是说事务开启成功,数据得到回滚。

 
 

6. 常见坑点

使用事务注解@Transactional 之前,应该先了解它的相关属性,避免在实际项目中踩中各种各样的坑点。

常见坑点1:遇到检测异常时,事务默认不回滚。

例如下面这段代码,账户余额依旧增加成功,并没有因为后面遇到SQLException(检测异常)而进行事务回滚!!

 @Transactional
public void addMoney() throws Exception {
//先增加余额
accountMapper.addMoney();
//然后遇到故障
throw new SQLException("发生异常了..");
}

原因分析:因为Spring的默认的事务规则是遇到运行异常(RuntimeException及其子类)和程序错误(Error)才会进行事务回滚,显然SQLException并不属于这个范围。如果想针对检测异常进行事务回滚,可以在@Transactional 注解里使用

rollbackFor 属性明确指定异常。例如下面这样,就可以正常回滚:

 @Transactional(rollbackFor = Exception.class)
public void addMoney() throws Exception {
//先增加余额
accountMapper.addMoney();
//然后遇到故障
throw new SQLException("发生异常了..");
}

常见坑点2: 在业务层捕捉异常后,发现事务不生效。

这是许多新手都会犯的一个错误,在业务层手工捕捉并处理了异常,你都把异常“吃”掉了,Spring自然不知道这里有错,更不会主动去回滚数据。例如:下面这段代码直接导致增加余额的事务回滚没有生效。

 @Transactional
public void addMoney() throws Exception {
//先增加余额
accountMapper.addMoney();
//谨慎:尽量不要在业务层捕捉异常并处理
try {
throw new SQLException("发生异常了..");
} catch (Exception e) {
e.printStackTrace();
}
}

不要小瞧了这些细节,往前暴露异常很大程度上很能够帮我们快速定位问题,而不是经常在项目上线后出现问题,却无法刨根知道哪里报错。

推荐做法:若非实际业务要求,则在业务层统一抛出异常,然后在控制层统一处理。

    @Transactional
public void addMoney() throws Exception {
//先增加余额
accountMapper.addMoney();
//推荐:在业务层将异常抛出
throw new RuntimeException("发生异常了..");
}

SpringBoot 快速开启事务(附常见坑点)的更多相关文章

  1. 详解SpringBoot 添加对JSP的支持(附常见坑点)

    序言: SpringBoot默认不支持JSP,如果想在项目中使用,需要进行相关初始化工作.为了方便大家更好的开发,本案例可直接作为JSP开发的脚手架工程 SpringBoot+War+JSP . 常见 ...

  2. Springboot 事务处理常见坑点

    使用事务注解@Transactional 之前,应该先了解它的相关属性,避免在实际项目中踩中各种各样的坑点. 常见坑点1:遇到非检测异常时,事务不开启,也无法回滚. 例如下面这段代码,账户余额依旧增加 ...

  3. springboot开启事务管理

    spring中开启事务管理需要在xml配置文件中配置,springboot中采取java config的配置方式. 核心是@EnableTransactionManager注解,该注解即为开启事务管理 ...

  4. 详解SpringBoot集成jsp(附源码)+遇到的坑

    本文介绍了SpringBoot集成jsp(附源码)+遇到的坑 ,分享给大家 1.大体步骤 (1)创建Maven web project: (2)在pom.xml文件添加依赖: (3)配置applica ...

  5. springboot 开启事务以及手动提交事务

    添加依赖,sprongboot 会默认开启事务管理 org.springframework.boot spring-boot-starter-jdbc 在需要的服务类里添加注解 @Autowired ...

  6. 记一次 Spring 事务配置踩坑记

    记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条 ...

  7. SPRING-BOOT系列之SpringBoot快速入门

    今天 , 正式来介绍SpringBoot快速入门 : 可以去如类似 https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/refer ...

  8. springboot快速使用

    1.编写SpringConfig 用于实例化Spring容器 @Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件 @Bean // 通过该注解来表明是 ...

  9. springboot 快速开发的定制补充

    增强 SpringBoot 快速开发工具 项目地址:https://gitee.com/sanri/web-ui 优点:这是一个 web 通用配置的组件,即插即用,可用于新项目或私活.是对 Sprin ...

  10. Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析

    一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...

随机推荐

  1. nginx日志按日期存储

    http {     include       mime.types;     default_type  application/octet-stream;     map $time_iso86 ...

  2. python exec_command 命令无效的原因

    当使用Python Paramiko exec_command执行时,某些Unix命令失败并显示"未找到"_互联网集市 (qyyshop.com) 链接里的解释解决了问题 本来直接 ...

  3. C++ primer 5th 第二章 变量和基本类型 阅读笔记

    第二章 变量和基本类型 第一节 基本内置类型 C++标准规定了算术类型尺寸的最小值,同时允许编译器赋予这些类型更大的尺寸. 比如: 类型 含义 最小尺寸 bool 布尔类型 未定义 wchar_t 宽 ...

  4. centos下安装部署nginx

    1.在安装Nginx之前,要确保已经安装了需要的软件:gcc.pcre-devel.zlib-devel.openssl-devel.如果没有安装,执行下面命令. yum -y install gcc ...

  5. RepVGG:一个结构重参数化网络

    ​  本文来自公众号"AI大道理" ResNet.DenseNet 等复杂的多分支网络可以增强模型的表征能力,使得训练效果更好.但是多分支的结构在推理的时候效率严重不足. 看起来二 ...

  6. wsl无法创建文件与修改文件

    wsl无法创建文件与修改文件 sudo chown -R username /home/your_folder/ 请将用户名换成你的用户名 且目录换成你想要操作的目录

  7. nop4.3 用户权限管理

    权限管理涉及到5张表: //用户表 select * from Customer //角色表select * from CustomerRole //用户和角色对应关系select * from Cu ...

  8. WPF中向下拉框中绑定枚举体

    1.枚举绑定combox的ItemsSourceItemsSource绑定的是个集合值,要想枚举绑定ItemsSource,首先应该想到的是把枚举值变成集合. 方法一:使用资源里的ObjectData ...

  9. 解决The following signatures couldn't be verified because the public key is not available: NO_PUBKEY FEEA9169307EA071 NO_PUBKEY 8B57C5C2836F4BEB

    问题 yang@k8s-master:/etc/apt/sources.list.d$ sudo apt update Get:1 https://mirrors.aliyun.com/kuberne ...

  10. Drone自动部署配置文件

    .drone.yml 点击查看代码 kind: pipeline # 定义对象类型,还有secret和signature两种类型 type: docker # 定义流水线类型,还有kubernetes ...