TRUNCATE TABLE t 和DELETE FROM t的区别

9 篇文章 1 订阅

背景

最近再工作中,遇到一个问题,就是再代码执行过程中,出现异常时并不会去回滚代码.导致数据不一致,最初以为是@Transactional这个注解没有生效

Spring中什么时候@Transactional会失效

  • 因为Spring事务是基于代理来实现的,所以某个加了@Transactional的方法只有是被代理对象调用时,那么这个注解才会生效,所以如果被代理对象来调用这个方法,那么@Transactional是不会失效的
  • 同时如果这个方法是private的,那么@Transactional也会失效,因为底层cglib是基于子父类来实现的,子类是不能重载父类的private方法的,所以无法很好的利用代理,也会导致@Transactional失效
  • 异常没有被正确抛出,那么@Transactional也会失效.@Transactional默认情况下只对未捕获的运行异常进行回滚,而对已检查异常不会回滚事务,默认只回滚RuntimeException,如果需要对特定异常进行回滚,可以使用rollbackFor属性来指定需要回滚的异常类型

经排查代码中不存在以上问题,后来才知道是SQL的问题,只因为使用了一条SQL:

TRUNCATE TABLE user

代码

使用代码模拟当时场景;

数据准备

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
    `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
    PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES ('be079b29ddc111eda9b20242ac110003', '张三', '北京市海淀区xx街道123号');
INSERT INTO `user` VALUES ('be079b53ddc111eda9b20242ac110003', '李四', '上海市徐汇区xx路456号');
INSERT INTO `user` VALUES ('be079b95ddc111eda9b20242ac110003', '王五', '广州市天河区xx街道789号');
INSERT INTO `user` VALUES ('be079ba4ddc111eda9b20242ac110003', '赵六', '深圳市南山区xx路321号');
INSERT INTO `user` VALUES ('be079bb8ddc111eda9b20242ac110003', '周七', '成都市高新区xx街道654号');
INSERT INTO `user` VALUES ('be079bc5ddc111eda9b20242ac110003', '黄八', '武汉市江汉区xx街道234号');
INSERT INTO `user` VALUES ('be079bd4ddc111eda9b20242ac110003', '罗九', '南京市秦淮区xx路567号');
INSERT INTO `user` VALUES ('be079be2ddc111eda9b20242ac110003', '钱十', '重庆市渝北区xx街道890号');
INSERT INTO `user` VALUES ('be079befddc111eda9b20242ac110003', '周十一', '长沙市岳麓区xx路432号');
INSERT INTO `user` VALUES ('be079bfbddc111eda9b20242ac110003', '吴十二', '西安市雁塔区xx街道765号');

涉及代码

service代码:

@Override
@Transactional(rollbackFor = Exception.class)
public void demo() {
    userMapper.truncateTable();
    // 模拟一个异常,测试是否回滚
    int i = 1 / 0;
    User user = new User();
    user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
    user.setName("番茄炒蛋");
    user.setAddress("北京市朝阳区");
    userMapper.insert(user);
}

具体sql:

<delete id="truncateTable">
    TRUNCATE TABLE user
</delete>

执行结果:
在这里插入图片描述
在这里插入图片描述

再出现异常时,并没有去回滚代码恢复原有的数据.

修改代码

具体sql:

<delete id="truncateTable">
    DELETE FROM user
</delete>

执行结果:
在这里插入图片描述
在这里插入图片描述

虽然还是会报错,但是会回滚事务,保证了数据的一致性

总结

TRUNCATE TABLE user和DELETE FROM user是用于删除关系数据库表中的数据的两种不同的SQL语句,它们之间有以下区别:

  1. 操作方式: TRUNCATE TABLE user是一种DDL(数据定义语言)语句,而DELETE FROM user是一种DML(数据操作语言)语句.DDL语句用于定义数据库结构,而DML语句用于对数据进行操作
  2. 速度: TRUNCATE TABLE user通常比DELETE FROM user更快,TRUNCATE 语句通过删除表中的所有数据并释放存储空间来执行操作.相比之下,DELETE 语句是逐行删除,需要遍历每一行并记录事务日志.因此它可能需要更长的时间来完成
  3. 事务日志: TRUNCATE TABLE user在执行前会将操作记录在事务日志中,以便可以回滚操作.但是TRUNCATE 操作不会被事务回滚所影响.相反,DELETE FROM user操作可以被事务回滚,可以通过回滚操作恢复已删除的数据
  4. 触发器: TRUNCATE TABLE user不会出发与表相关的触发器,而DELETE FROM user会触发表相关的删除触发器.触发器是在数据库表上定义的一种特殊操作,它会在特定事件发生时自动出发相关的操作
  5. 权限要求: TRUNCATE TABLE user通常需要更高的权限才能执行,因为它是一种DDL语句.相比之下,DELETE FROM user是一种DML语句,对于具有适当权限的用户来说更容易执行

总结起来,TRUNCATE TABLE user是一种快速且非常有效的删除表数据的方法,不会触发触发器,并且不能被事务回滚,而DELETE FROM user是一种逐行删除数据的方法,可以出发触发器,并且可以通过事务回滚来恢复已删除的数据.选择使用那种语句取决于具体的需求和情况.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

.番茄炒蛋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值