Spring事务系列 一

第一章 Spring中事务的实现



前言

MySQL中有事务的概念,关于事务,Spring也进行了实现,以下是Spring声明式事务实现方式的简介。


提示:以下是本篇文章正文内容,下面案例可供参考

一、事务是什么?

事务是为了完成某个任务所进行的一组操作,这组操作是不可分割的,也可以说具备原子性。

事务会把这组操作视作一个整体:

当组内的所有操作都成功时,事务才成功,Spring会向数据库提交事务;

如果组内有一个操作失败了,那么事务就失败了,Spring会把事务进行回滚;

二、事务的分类

Spring中将事务分为两类,编程式事务和声明式事务。

编程式事务是通过手动写代码,操作事务;

声明式事务是通过使用注解@Transactional,自动实现事务的开启,提交以及回滚;

本文主要介绍声明式事务。

三、@Transactional注解

@Transactional可以实现自动开启,提交以及回滚事务。

@Transactional可以作用于类,也可以作用于方法。

作用于类,表示这个类中所有的用public修饰的方法都使用了@Transactional注解修饰;

作用于方法,表示该方法使用@Transactional注解修饰;

@Transactional的作用:

1)当方法运行成功时,自动提交事务;

2)程序运行出现错误或者运行时异常时:

  1. 异常没有被捕获,事务回滚;
  2. 异常被捕获,事务提交:

3)异常被捕获,如果想回滚事务,有两种方式:

  1. 重新抛出异常;
  2. 手动回滚事务;

4)程序出现受查异常时:

  1. 自动提交事务;
  2. 如果想回滚事务,需要通过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声明式事务的实现以及演示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值