第一章 Spring中事务的实现
文章目录
前言
MySQL中有事务的概念,关于事务,Spring也进行了实现,以下是Spring声明式事务实现方式的简介。
提示:以下是本篇文章正文内容,下面案例可供参考
一、事务是什么?
事务是为了完成某个任务所进行的一组操作,这组操作是不可分割的,也可以说具备原子性。
事务会把这组操作视作一个整体:
当组内的所有操作都成功时,事务才成功,Spring会向数据库提交事务;
如果组内有一个操作失败了,那么事务就失败了,Spring会把事务进行回滚;
二、事务的分类
Spring中将事务分为两类,编程式事务和声明式事务。
编程式事务是通过手动写代码,操作事务;
声明式事务是通过使用注解@Transactional,自动实现事务的开启,提交以及回滚;
本文主要介绍声明式事务。
三、@Transactional注解
@Transactional可以实现自动开启,提交以及回滚事务。
@Transactional可以作用于类,也可以作用于方法。
作用于类,表示这个类中所有的用public修饰的方法都使用了@Transactional注解修饰;
作用于方法,表示该方法使用@Transactional注解修饰;
@Transactional的作用:
1)当方法运行成功时,自动提交事务;
2)程序运行出现错误或者运行时异常时:
- 异常没有被捕获,事务回滚;
- 异常被捕获,事务提交:
3)异常被捕获,如果想回滚事务,有两种方式:
- 重新抛出异常;
- 手动回滚事务;
4)程序出现受查异常时:
- 自动提交事务;
- 如果想回滚事务,需要通过rollbackFor设置;
四、@Transactional注解作用演示
下面结合代码进行演示:
1. 准备工作:
引入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.4</version>
<scope>test</scope>
</dependency>
</dependencies>
使用数据层(mapper),服务层(service),表现层(controller)三层架构,结合对象(model),以及数据库进行演示:
model:
@Data
public class UserInfo {
private Integer id;
private String userName;
private String password;
private Date createTime;
private Date updateTime;
}
mapper:
@Mapper
public interface UserInfoMapper {
@Insert("insert into user_info (user_name, password) values (#{userName}, #{password})")
Integer insertUserInfo(String userName, String password);
}
service:
@Service
public class UserInfoService {
@Autowired
private UserInfoMapper userInfoMapper;
public Integer insertUserInfo(String userName, String password) {
return userInfoMapper.insertUserInfo(userName, password);
}
}
controller:
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {
@Autowired
private UserInfoService userInfoService;
// 演示所用的方法都放在这里
//
}
数据库表:初始为空
2. 当方法运行成功时,自动提交事务
代码如下(示例):
/**
* 程序运行正常 - 自动提交
*/
@Transactional
@RequestMapping("/insert")
public Boolean insertUserInfo(String userName, String password){
Integer result = userInfoService.insertUserInfo(userName, password);
return true;
}
查询数据库信息,插入成功:
3. 程序运行出现错误或者异常
以异常为例进行演示事务自动回滚,代码如下(示例):
/**
* 程序运行异常 - 自动回滚
*/
@Transactional
@RequestMapping("/r1")
public Boolean r1(String userName, String password){
Integer result = userInfoService.insertUserInfo(userName, password);
throw new RuntimeException();
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,数据库中没有姓名为libai1的信息,原因是事务实现了自动回滚:
以异常为例进行演示事务提交,代码如下(示例):
@Transactional
@RequestMapping("/r3")
public Boolean r3(String userName, String password){
try{
Integer result = userInfoService.insertUserInfo(userName, password);
if(result > 0){
Integer ret = 10 / 0;
return true;
}
return false;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,虽然出现异常,但是捕获成功,信息任然插入成功:
注意:这次插入时id更新为23,而不是22,说明上次插入时事务的确实现了回滚。
4. 程序运行时异常被捕获,实现回滚的方式
重新抛出异常,代码如下(示例):
/**
* 程序异常,捕获异常,重新抛出异常,实现回滚
*/
@Transactional
@RequestMapping("/r4")
public Boolean r4(String userName, String password){
try{
Integer result = userInfoService.insertUserInfo(userName, password);
if(result > 0){
Integer ret = 10 / 0;
return true;
}
return false;
}catch (Exception e){
throw e;
}
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,数据库中没有姓名为libai2的信息,原因是事务实现了自动回滚:
手动实现回滚,代码如下(示例):
/**
* 程序异常,捕获异常,手动实现回滚
*/
@Transactional
@RequestMapping("/r5")
public Boolean r5(String userName, String password){
try{
Integer result = userInfoService.insertUserInfo(userName, password);
if(result > 0){
Integer ret = 10 / 0;
return true;
}
return false;
}catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return false;
}
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,数据库中没有姓名为libai2的信息,原因是事务实现了自动回滚:
重新插入一条新的信息,查询数据库:
注意:这次插入时id更新为26,中间跳过了24和25,说明前两次插入时事务的确实现了回滚。
5. 程序出现受查异常
出现受查异常自动提交事务,代码如下(示例):
/**
* 程序存在受查异常,自动提交
*/
@Transactional
@RequestMapping("/r6")
public Boolean r6(String userName, String password) throws IOException {
Integer result = userInfoService.insertUserInfo(userName, password);
if(result > 0){
throw new IOException();
}
return false;
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,数据库出现姓名为libai3的信息,插入成功:
出现受查异常,设置rollbackFor实现回滚,代码如下(示例):
/**
* 程序存在受查异常,通过设置rollbackFor,实现自动回滚
*/
@Transactional(rollbackFor = Exception.class)
@RequestMapping("/r7")
public Boolean r7(String userName, String password) throws IOException {
Integer result = userInfoService.insertUserInfo(userName, password);
if(result > 0){
throw new IOException();
}
return false;
}
使用浏览器插入用于信息,进行测试:
查询数据库信息,数据库中没有姓名为libai4的信息,原因是事务实现了自动回滚:
重新插入一条新的信息,查询数据库:
注意:这次插入时id更新为29,中间跳过了28,说明前一次插入时事务的确实现了回滚。
总结
以上就是Spring声明式事务的实现以及演示。