不学编程都能看懂的@Transactional()事务

后端三郎:一名99年的宝藏开发男孩儿

看咱关系:文章对你有用的话,点赞打卡


目录

背景原因

框架版本

代码示例

表结构和数据

MjjFoodModel实体类

Controller方法

FoodService 接口

FoodServiceImpl 实现类

MjjFoodModelMapper接口

不加事务结果

使用事务结果

属性用法


背景原因

        假设我们接口修改数据,接口处理了一半,数据已经入库了,处理另一半的时候报错了,此时我们要保证已经处理完的数据回滚到未处理之前,保证数据的原子性。

        Spring的@Transactional注解可以很方便的开启事务,但是默认只在遇到运行时异常和Error时才会回滚,非运行时异常不回滚,即Exception的子类中,除了RuntimeException及其子类,其他的类默认不回滚。

框架版本

SpringBoot——2.4.1

Lombok——1.18.16

Mybatis-Plus——3.4.2

MySql——8.0.22

代码示例

表结构和数据

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for mjj_food_model
-- ----------------------------
DROP TABLE IF EXISTS `mjj_food_model`;
CREATE TABLE `mjj_food_model`  (
  `id` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键ID(uuid)',
  `food_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食名称',
  `food_brief` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食简介',
  `food_picture` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '美食图片',
  `city_id` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '城市ID',
  `city_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '城市名称',
  `create_id` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人ID',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_id` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '修改人ID',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  `is_delete` tinyint(1) NULL DEFAULT NULL COMMENT '是否删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '美食特产表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of mjj_food_model
-- ----------------------------
INSERT INTO `mjj_food_model` VALUES ('c525acf0-7763-11ec-996d-00163e0c3e0d', '牛肉丸子面', '临汾以牛肉丸子面最为有名,属于清真美食,牛肉丸子汤遍布临汾,一碗端上来,厚厚的红油看着就很有食欲,汤底是用牛骨高汤熬制,有嚼劲的丸子和劲道的面相互搭配,再加上青菜点缀,吃起来香、辣、麻,一碗下肚,很是过瘾。', '牛肉面图片', '167fa911-776e-11ec-996d-00163e0c3e0d', '临汾', '1', '2022-01-18 15:16:58', '1', '2022-01-18 15:17:05', 1);

SET FOREIGN_KEY_CHECKS = 1;

MjjFoodModel实体类

package com.example.demo.entity.food;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@AllArgsConstructor//有参构造方法
@NoArgsConstructor//无参构造方法
@Data
public class MjjFoodModel {

    /**
     *美食特产主键ID
     */
    private String id;

    /**
     *美食名称
     */
    private String foodName;

    /**
     *美食简介
     */
    private String foodBrief;

    /**
     *美食图片
     */
    private String foodPicture;

    /**
     *城市ID
     */
    private String cityId;

    /**
     *城市名称
     */
    private String cityName;

    /**
     *创建人ID
     */
    private String createId;

    /**
     *创建时间
     */
    private LocalDateTime createTime;

    /**
     *修改人ID
     */
    private String updateId;

    /**
     *修改时间
     */
    private LocalDateTime updateTime;

    /**
     *是否删除 true(1)未删除 false(0)删除
     */
    private Boolean isDelete;

}

Controller方法

@RestController
@RequestMapping(value = "/food")
//swagger注解,不用可以删除
@Api(value = "后端三郎and前端小马",tags = "李淳罡VS曹长卿————美食模块")
public class FoodController {

    @Resource
    private FoodService foodService;

    @GetMapping(value = "/save")
    //swagger注解,不用可以删除
    @ApiOperation(value = "美食特产编辑",httpMethod = "GET",notes = "美食特产编辑")
    public void save(){
        foodService.save();
    }
}

FoodService 接口

    void save();

FoodServiceImpl 实现类

    
    @Resource
    private MjjFoodModelMapper mjjFoodModelMapper;

    @Override
    public void save() {
        //创建实体类
        MjjFoodModel mjjFoodModel = new MjjFoodModel();
        //复制主键ID为UUID
        mjjFoodModel.setId(UUID.randomUUID().toString());
        //美食名称
        mjjFoodModel.setFoodName("美食名称");
        //新增
        mjjFoodModelMapper.insert(mjjFoodModel);
        //写个BUG,使程序出现错误
        int a = 4/0;
    }

MjjFoodModelMapper接口

@Mapper
public interface MjjFoodModelMapper extends BaseMapper<MjjFoodModel> {


}

不加事务结果

        启动项目,访问localhost:8081/food/save测试(端口号自己配置的)

             注:500的错误是我们故意写错的,为了看数据是否会回滚

         接口运行一半报错,此时我们查看数据发现数据却添加进去了,此时会对我们的数据造成脏数据,因为报错了你再次请求的时候就会有多条数据。不符合我们的业务逻辑。

使用事务结果

        在FoodServiceImpl 实现类的save方法上边加上@Transactional注解,再次测试

    @Override
    @Transactional
    public void save() {
        //创建实体类
        MjjFoodModel mjjFoodModel = new MjjFoodModel();
        //复制主键ID为UUID
        mjjFoodModel.setId(UUID.randomUUID().toString());
        //美食名称
        mjjFoodModel.setFoodName("美食名称");
        //新增
        mjjFoodModelMapper.insert(mjjFoodModel);
        //写个BUG,使程序出现错误
        int a = 4/0;
    }

         启动项目,访问localhost:8081/food/save测试,接口依然报错,但是我们的数据没有添加进去,遇到异常数据进行了回滚。数据还是保持原样。

属性用法

readOnly:读写或只读事务,true代表只读,false代表读写,默认读写false,例如@Transactional(readOnly = true)。

rollbackFor:解决了只有运行时异常和Error才回滚的问题,用于指定回滚的异常类型。例如@Transactional(rollbackFor = Exception.class),用的Exception顶级异常,包含了所有的子类,所有的异常都可以回滚。

noRollbackFor:意思是遇到异常不进行回滚,例如@Transactional(rollbackFor = Exception.class),用的Exception顶级异常,包含了所有的子类,所有的异常都不回滚。和上一个正好相反。

propagation:事务的传播行为,默认的是REQUIRED

  •   REQUIRED 支持当前已经存在的事务,如果还没有事务,就创建一个新事务。
  •   MANDATORY 支持当前已经存在的事务,如果还没有事务,就抛出一个异常。
  •   NESTED 在当前事务中创建一个嵌套事务,如果还没有事务,那么就简单地创建一个新事务。
  •   REQUIRES_NEW 挂起当前事务,创建一个新事务,如果还没有事务,就简单地创建一个新事务。
  •   NEVER 强制要求不在事务中运行,如果当前存在一个事务,则抛出异常。
  •   NOT_SUPPORTED 强制不在事务中运行,如果当前存在一个事务,则挂起该事务。
  •   SUPPORTS 支持当前事务,如果没有事务那么就不在事务中运行。

timeout:事务的超时设置,如果超过该时间限制但事务还没有完成,则自动回滚事务。默认没有时间限制。

isolation:事务的隔离级别,使用默认的即可

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后端三郎@ZYJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值