SpringDataJPA使用deleteAllInBatch方法逻辑删除失效

概述

在使用Spring Boot JPA时,执行批量删除操作时,遇到逻辑删除失效的问题。具体而言,当使用deleteAllInBatch方法时,数据会被物理删除,而不是进行逻辑删除;但是当使用deleteAll时,逻辑删除操作可以正常生效。经过调查,发现deleteAllInBatch方法和deleteAll方法的行为有所不同,导致逻辑删除失败。

症状

  • 使用deleteAllInBatch方法时,数据直接从数据库中物理删除。
  • 使用deleteAll方法时,逻辑删除生效,数据并未被物理删除,而是更新了delLogic字段。

使用的实体类代码

@Entity
public class TemplateField {@Idprivate Long id;private Integer delLogic;  // 用于标记是否被逻辑删除@PreRemovepublic void templateField() {this.setDelLogic(1);  // 设置逻辑删除标记}@SQLDelete(sql = "UPDATE t_template_field SET del_logic = 1 WHERE id = ?")@Where(clause = "del_logic = 0")  // 过滤删除标记为0的数据public void setDelLogic(Integer delLogic) {this.delLogic = delLogic;}
}

问题原因

问题的根本原因是deleteAllInBatchdeleteAll在执行删除操作时的实现方式不同,导致生命周期回调方法(如@PreRemove)未被触发。

deleteAllInBatchdeleteAll的区别

  1. deleteAll():该方法会逐个加载实体,并在JPA上下文中处理每个实体的删除操作。每次删除实体时,都会触发实体的生命周期回调方法(如@PreRemove@PostRemove等)。因此,当使用deleteAll()方法时,你在实体类上定义的逻辑删除(例如通过@PreRemove标记设置删除标记)可以生效。

  2. deleteAllInBatch():该方法是一个批量删除操作,通常是直接生成SQL语句一次性删除数据,不会逐个加载实体,因此也不会触发实体的生命周期回调方法。批量操作的优势在于效率较高,但缺点是无法触发与实体相关的生命周期事件,如@PreRemove@PostRemove

deleteAllInBatch导致物理删除的原因

deleteAllInBatch()方法并不会按@PreRemove中的逻辑设置delLogic字段,而是直接执行数据库的物理删除操作。这就是为什么在使用deleteAllInBatch()时,数据会被直接从数据库中删除,而不是进行逻辑删除的原因。


问题解决方案

要解决这个问题,通常有以下几种方式:

方案 1:使用deleteAll()替代deleteAllInBatch()

如果逻辑删除的需求比性能更为重要,并且不介意性能稍微下降,可以直接使用deleteAll()方法。这会逐个处理实体,并触发相应的生命周期回调方法,从而确保逻辑删除(即更新delLogic字段)生效。

方案 2:自定义批量更新方法

如果依然希望使用批量删除操作(如deleteAllInBatch()),可以自定义一个批量更新的方法,通过直接执行SQL更新操作来实现逻辑删除。这种方式可以保证批量操作时的效率,同时避免物理删除数据。

例如,使用@Modifying@Query注解,执行批量更新操作:

@Modifying
@Query("UPDATE TemplateField tf SET tf.delLogic = 1 WHERE tf.id IN :ids")
int batchLogicalDelete(@Param("ids") List<Long> ids);

该方法会直接更新符合条件的记录,将delLogic字段设置为1,达到逻辑删除的效果。

方案 3:手动更新实体后再执行批量删除

可以先通过查询获取所有需要“删除”的实体,将它们的delLogic字段设置为逻辑删除标志,然后再调用deleteAllInBatch()进行删除操作。

代码示例:

List<TemplateField> fields = templateFieldRepository.findAllById(ids);
fields.forEach(field -> field.setDelLogic(1));  // 更新逻辑删除标志
templateFieldRepository.saveAll(fields);  // 保存更新
templateFieldRepository.deleteAllInBatch(fields);  // 执行批量删除

这种方式在批量删除前,先手动更新实体,确保逻辑删除字段被正确设置。


问题示例代码

使用deleteAll()进行逻辑删除

List<TemplateField> fields = templateFieldRepository.findAllById(ids);
fields.forEach(field -> field.setDelLogic(1));  // 更新逻辑删除标志
templateFieldRepository.saveAll(fields);  // 保存更新
templateFieldRepository.deleteAll(fields);  // 执行逐个删除(触发生命周期方法)

自定义批量更新方法进行逻辑删除

@Modifying
@Query("UPDATE TemplateField tf SET tf.delLogic = 1 WHERE tf.id IN :ids")
int batchLogicalDelete(@Param("ids") List<Long> ids);// 调用自定义批量逻辑删除方法
templateFieldRepository.batchLogicalDelete(ids);

手动更新实体后再执行批量删除

List<TemplateField> fields = templateFieldRepository.findAllById(ids);
fields.forEach(field -> field.setDelLogic(1));  // 更新逻辑删除标志
templateFieldRepository.saveAll(fields);  // 保存更新
templateFieldRepository.deleteAllInBatch(fields);  // 执行批量删除

总结

  • deleteAllInBatch()方法直接执行SQL批量删除,不会触发实体的生命周期回调方法(如@PreRemove),导致逻辑删除无效。
  • 如果需要触发回调方法,可以使用deleteAll(),但会影响性能。
  • 也可以自定义批量逻辑删除方法,通过直接更新delLogic字段来避免物理删除。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/70940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】使用Docker搭建-MySQL数据库服务

零、更换Docker镜像源 因为国内现在封锁了Docker默认拉取镜像的站点&#xff08;DockerHub&#xff09;&#xff0c;而且国内大部分Docker镜像站已全部下线&#xff0c;导致现在很多朋友在拉取镜像的时候会出现无法拉取的现象&#xff0c;这时候就需要进行更换Docker镜像源。 可…

人类驾驶的人脑两种判断模式(反射和预判)-->自动驾驶两种AI模式

一种模式是直觉模式&#xff0c;判断基于条件反射&#xff0c;视觉感知 触发到 直接条件反射&#xff08;从经历中沉淀形成的神经信息闭环&#xff09;&#xff0c;类似现在自动驾驶技术的传统AI模式&#xff1b;另一种是图式推理模式&#xff0c;判断是基于预判&#xff0c;人…

3.17 AI Agent 场景革命:解锁企业级应用的 15 个黄金赛道

AI Agent 场景革命:解锁企业级应用的 15 个黄金赛道 关键词:AI Agent 应用场景, 企业级智能体案例, 多模态 Agent 实现, 工具链自动化, 智能决策系统 1. 企业级 Agent 场景分类图谱 #mermaid-svg-UjUmmToEKigfdlFf {font-family:"trebuchet ms",verdana,arial,san…

Docker基础-常见命令

docker images -查看所有的本地镜像。 docker pull -把远端镜像拉取到本地。 docker rmi -删除镜像。 docker push -推到镜像仓库。 docker run -创建并运行容器&#xff08;自动化&#xff0c;如果发现镜像不存在会先去拉取&#xff0c; 拉取完了以后再去自动创建容器&am…

TinyEngine v2.2版本发布:支持页面嵌套路由,提升多层级路由管理能力开发分支调整

2025年春节假期已过&#xff0c;大家都带着慢慢的活力回到了工作岗位。为了让大家在新的一年继续感受到 Tiny Engine 的成长与变化&#xff0c;我们很高兴地宣布&#xff1a;TinyEngine v2.2版本正式发布&#xff01;本次更新带来了重要的功能增强------页面支持嵌套路由&#…

LSTM长短期记忆网络-原理分析

1 简介 概念 LSTM&#xff08;Long Short-Term Memory&#xff09;也称为长短期记忆网络&#xff0c;是一种改进的循环神经网络&#xff08;RNN&#xff09;&#xff0c;专门设计用于解决传统RNN的梯度消失问题和长程依赖问题。LSTM通过引入门机制和细胞状态&#xff0c;能够更…

SQL Server 中遇到的常见问题集

SQL Server 中遇到的常见问题集 问题一&#xff1a; 无法创建关系“FK_Research_Teacher”。 ALTER TABLE 语句与 FOREIGN KEY 约束"FK_Research_Teacher"冲突 解决方法&#xff1a; 外键表中的数据主键表中是有的&#xff0c;并且不能删除主外键表中数据 1&…

神经网络中感受野的概念和作用

在神经网络中&#xff0c;感受野&#xff08;Receptive Field&#xff09;是指某个神经单元&#xff08;神经元或者卷积核&#xff09;关注的输入特征区域的大小。它决定了神经网络对输入数据的特定区域的感知能力。 感受野的形成过程 在卷积神经网络中&#xff0c;卷积层是感受…

unreal engine gameplay abiliity 获取ability的cooldown剩余时间

unreal engine gameplay abiliity 获取ability的cooldown 版本 5.4.4 参考 测试代码 if (HasAuthority() && AbilitySystemComponent){TArray<FGameplayAbilitySpecHandle> OutAbilityHandles;AbilitySystemComponent->GetAllAbilities(OutAbilityHandles…

【leetcode hot 100 42】接雨水

错误解法&#xff1a;若height[left]>height[right]则代表有坑 class Solution {public int trap(int[] height) {int left 0;int area 0;while(left<height.length-1){// 找坑int right left1;while(right<height.length-1 && height[left]>height[ri…

Spark map与mapPartitions算子源码级深度解析

Spark map与mapPartitions算子源码级深度解析 一、核心源码结构差异 1. map算子实现逻辑 def map[U: ClassTag](f: T => U): RDD[U] = withScope {val cleanF = sc.clean(f)new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.map(cleanF)) }实现特征: …

【前端进阶】09 编程思维:从事件驱动到数据驱动

事件驱动与数据驱动 GUI与事件事件驱动数据驱动事件驱动和数据驱动的区别 GUI与事件 JavaScript作为浏览器的脚本语言&#xff0c;主要用途是与用户互动、操作DOM&#xff0c;实现页面UI和DOM操作&#xff0c;属于GUI&#xff08;图形用户界面&#xff09;编程 GUI程序注重用…

WPF-3天快速WPF入门并达到企业级水准

嘿&#xff0c;小伙伴们&#xff01;如果你已经有一定的C#开发基础&#xff0c;但想快速掌握WPF开发&#xff0c;达到企业级水准&#xff0c;那接下来的这个三天快速入门计划绝对适合你&#xff01;虽然听起来有点挑战&#xff0c;但别担心&#xff0c;只要跟着这个高强度、结构…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.3.1单节点安装(Docker与手动部署)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 10分钟快速部署Elasticsearch单节点环境1. 系统环境要求1.1 硬件配置推荐1.2 软件依赖 2. Docker部署方案2.1 部署流程2.2 参数说明2.3 性能优化建议 3. 手动部署方案3.1 安…

小程序中的插槽(Slot)机制及其与 Vue 组件的异同

小程序中的插槽&#xff08;Slot&#xff09;机制及其与 Vue 组件的异同 引言 在小程序开发中&#xff0c;组件化开发是一种重要的设计模式&#xff0c;而插槽&#xff08;Slot&#xff09;机制则是实现组件内容分发的关键。通过插槽&#xff0c;开发者可以更灵活地构建可复用…

vscode下载安装教程(附安装包)vscode图文安装教程最新版

文章目录 一、vscode下载二、vscod安装教程1.启动vscode安装程序&#xff1a;2.应对提示&#xff1a;3.接受协议&#xff1a;4.更改vscode安装路径&#xff1a;5.推进安装vscode&#xff1a;6.创建vscode快捷方式&#xff1a;7.开始安装vscode&#xff1a;8.完成vscode安装&…

Redis 缓存穿透、击穿、雪崩:问题与解决方案

在使用 Redis 作为缓存中间件时&#xff0c;系统可能会面临一些常见的问题&#xff0c;如 缓存穿透、缓存击穿 和 缓存雪崩。这些问题如果不加以解决&#xff0c;可能会导致数据库压力过大、系统响应变慢甚至崩溃。本文将详细分析这三种问题的起因&#xff0c;并提供有效的解决…

智能客服进化论:AI呼叫中心系统如何重塑企业服务竞争力?

导语&#xff1a;当客户咨询量激增300%时&#xff0c;你的客服团队还能从容应对吗&#xff1f; 在数字化转型加速的今天&#xff0c;企业客户服务正经历从"人力密集型"向"智能集约化"的质变。AI呼叫中心系统作为这场变革的核心引擎&#xff0c;已帮助超过…

异常c/c++

目录 1.c语言传统处理错误方式 1、终止程序 2、返回错误码 2.c异常概念 3.异常的使用 3.1异常的抛出与捕获 3.2异常安全&#xff08;还有一些异常重新抛出&#xff09; 3.3异常规范 4.自定义异常体系 5.c标准库的异常体系 6.异常优缺点 1、优点 2、缺点 7、补充 1.…

ChatGPT 提示词框架

作为一个资深安卓开发工程师&#xff0c;我们在日常开发中经常会用到 ChatGPT 来提升开发效率&#xff0c;比如代码优化、bug 排查、生成单元测试等。 但要想真正发挥 ChatGPT 的潜力&#xff0c;我们需要掌握一些提示词&#xff08;Prompt&#xff09;的编写技巧&#xff0c;并…