Springboot + MySQL+ JPA Ⅲ delete方法详解

news2024/10/1 17:31:39

一、deleteById(Id id) 和 delete(T entity)

为什么要把这两个方法放在一起呢?我们先看源码再说

deleteById源码(通过id进行删除)

@Transactional
@Override
public void deleteById(ID id) {

   Assert.notNull(id, ID_MUST_NOT_BE_NULL);

   delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
         String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
}
复制代码

delete源码(通过实体对象进行删除)

@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {

   Assert.notNull(entity, "Entity must not be null!");

   if (entityInformation.isNew(entity)) {
      return;
   }

   Class<?> type = ProxyUtils.getUserClass(entity);

   T existing = (T) em.find(type, entityInformation.getId(entity));

   // if the entity to be deleted doesn't exist, delete is a NOOP
   if (existing == null) {
      return;
   }

   em.remove(em.contains(entity) ? entity : em.merge(entity));
}
复制代码

一目了然了吧!deleteById先在方法体内通过id求出entity对象,然后调用了delete的方法。也就是说,这两个方法同根同源,使用起来差距不大,结果呢?也是一样的,就是单条删除。实际使用中呢,也是使用deleteById的情况比较多,废话少说,try it。

Service层中添加deleteById方法(deleteById是三方件自带接口不需要在dao层中添加)

@Transactional
public void deleteById(Integer id){
    userDao.deleteById(id);
}
复制代码

control层

/**
 * 通过id进行删除数据
 * @param id
 */
@GetMapping("/deleteById")
public void deleteById(Integer id){
	userService.deleteById(id);
}
复制代码

浏览器测试成功 http://localhost:7777/deleteById?id=2


控制台打印了两行sql,如下:

Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: delete from user where id=?
复制代码

由此可见,先通过select看看实体对象是否存在,然后再通过id进行删除!

二、deleteAllById(Iterable<? extends ID> ids) 和 deleteAll(Iterable<? extends T> entities)

deleteAllById(Iterable<? extends ID> ids)(通过id进行批量删除)

@Override
@Transactional
public void deleteAllById(Iterable<? extends ID> ids) {

   Assert.notNull(ids, "Ids must not be null!");

   for (ID id : ids) {
      deleteById(id);
   }
}
复制代码

通过源码可以看出,就是遍历ids然后循环调用上面的deleteById(Id id)方法。

deleteAll(Iterable<? extends T> entities)(通过实体对象进行批量删除)

@Override
@Transactional
public void deleteAll(Iterable<? extends T> entities) {

   Assert.notNull(entities, "Entities must not be null!");

   for (T entity : entities) {
      delete(entity);
   }
}
复制代码

这个呢?也就是遍历entities然后循环调用上面的delete(T entity)方法

还有一个不传参数的deleteAll()方法来删除所有数据(慎用)

@Override
@Transactional
public void deleteAll() {

   for (T element : findAll()) {
      delete(element);
   }
}
复制代码

就是通过findAll求出所有实体对象然后循环调用delete方法

综上所述,我们发现以上所有的删除事件都是调用了delete(T entity)方法,也就是差距不是很大,就是单条 和多条删除的区别。

让我们来测试一下多条删除的场景:
Service层中添加deleteAllById方法(deleteAllById是三方件自带接口不需要在dao层中添加)

@Transactional
public void deleteAllById(Iterable ids){
	userDao.deleteAllById(ids);
}
复制代码

control层

/**
 * 通过id进行批量删除
 * @param ids
 */
@GetMapping("/deleteAllById")
public void deleteAllById(Integer[] ids){
	userService.deleteAllById(Arrays.asList(ids));
}
复制代码

浏览器测试成功 http://localhost:7777/deleteAllById?id=3,4
删除前:


删除后:

控制台打印如下:

Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: delete from user where id=?
Hibernate: delete from user where id=?
复制代码

由此可以看出,数据是一条一条的进行了删除。

三、deleteAllInBatch(Iterable entities)和deleteAllByIdInBatch(Iterable ids)

deleteAllInBatch(Iterable entities)源码(通过实体对象进行批量删除)

public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";

@Override
@Transactional
public void deleteAllInBatch(Iterable<T> entities) {

   Assert.notNull(entities, "Entities must not be null!");

   if (!entities.iterator().hasNext()) {
      return;
   }

   applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
         .executeUpdate();
}
复制代码
/**
 * Creates a where-clause referencing the given entities and appends it to the given query string. Binds the given
 * entities to the query.
 *
 * @param <T> type of the entities.
 * @param queryString must not be {@literal null}.
 * @param entities must not be {@literal null}.
 * @param entityManager must not be {@literal null}.
 * @return Guaranteed to be not {@literal null}.
 */

public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {

   Assert.notNull(queryString, "Querystring must not be null!");
   Assert.notNull(entities, "Iterable of entities must not be null!");
   Assert.notNull(entityManager, "EntityManager must not be null!");

   Iterator<T> iterator = entities.iterator();

   if (!iterator.hasNext()) {
      return entityManager.createQuery(queryString);
   }

   String alias = detectAlias(queryString);
   StringBuilder builder = new StringBuilder(queryString);
   builder.append(" where");

   int i = 0;

   while (iterator.hasNext()) {

      iterator.next();

      builder.append(String.format(" %s = ?%d", alias, ++i));

      if (iterator.hasNext()) {
         builder.append(" or");
      }
   }

   Query query = entityManager.createQuery(builder.toString());

   iterator = entities.iterator();
   i = 0;

   while (iterator.hasNext()) {
      query.setParameter(++i, iterator.next());
   }

   return query;
}
复制代码

通过上面的源码,我们大体能猜测出deleteAllInBatch(Iterable entities)的实现原理:
delete from %s where x=? or x=?
实际测试一下:http://localhost:7777/deleteAllInBatch?ids=14,15,16&names=a,b,c&ages=0,0,0
控制台打印如下:

Hibernate: delete from user where id=? or id=? or id=?
复制代码

deleteAllByIdInBatch(Iterable ids)源码(通过ids批量删除)


public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where %s in :ids";

@Override
@Transactional
public void deleteAllByIdInBatch(Iterable<ID> ids) {

   Assert.notNull(ids, "Ids must not be null!");

   if (!ids.iterator().hasNext()) {
      return;
   }

   if (entityInformation.hasCompositeId()) {

      List<T> entities = new ArrayList<>();
      // generate entity (proxies) without accessing the database.
      ids.forEach(id -> entities.add(getReferenceById(id)));
      deleteAllInBatch(entities);
   } else {

      String queryString = String.format(DELETE_ALL_QUERY_BY_ID_STRING, entityInformation.getEntityName(),
            entityInformation.getIdAttribute().getName());

      Query query = em.createQuery(queryString);
      /**
       * Some JPA providers require {@code ids} to be a {@link Collection} so we must convert if it's not already.
       */
      if (Collection.class.isInstance(ids)) {
         query.setParameter("ids", ids);
      } else {
         Collection<ID> idsCollection = StreamSupport.stream(ids.spliterator(), false)
               .collect(Collectors.toCollection(ArrayList::new));
         query.setParameter("ids", idsCollection);
      }

      query.executeUpdate();
   }
}
复制代码

通过上面源码我们大体可以猜出deleteAllByIdInBatch(Iterable ids)的实现原理:
delete from %s where id in (?,?,?)
实际测试一下:http://localhost:7777/deleteAllByIdInBatch?ids=17,18,19 控制台打印如下:

Hibernate: delete from user where id in (? , ? , ?)
复制代码

这里同样有个不带参数的deleteAllInBatch()的方法,源码如下:

@Override
@Transactional
public void deleteAllInBatch() {
   em.createQuery(getDeleteAllQueryString()).executeUpdate();
}

public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";

private String getDeleteAllQueryString() {
   return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName());
}

复制代码

通过源码不难猜到实现原理吧,多的不说,直接给测试的控制台数据:
Hibernate: delete from user

最终结论:

从上面两种删除接口来看,第二种实现比起第一种更加的快捷;第一种就是一条一条的进行删除操作,如果有万级的数据,执行起来肯定非常耗时,所以如果数据量比较大的话,还是建议大家使用第二种。

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

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

相关文章

@爱打游戏的你,当游戏测试是什么感觉?

爱打游戏的你&#xff0c;当游戏测试是一种什么感觉&#xff1f; 去年《宝可梦朱紫》大火的那段时间&#xff0c;想必各位爱好游戏的友友们都刷到过这样的图吧&#xff1a;&#xff08;量子纠缠&#xff09;&#xff08;天怎么黑了&#xff09;&#xff08;弹簧巨怪&#xff09…

手敲Mybatis(九)-结果集处理器

1.前言-背景介绍 上节我们处理了参数处理器&#xff0c;本节我们处理结果集处理器&#xff0c;之前我们写了一个DefaultResultSetHandler&#xff0c;我们把返回结果获取对象&#xff0c;填充值什么的写到了一起&#xff0c;流程没有进行解耦&#xff0c;并且只接收了Object的…

不通过鲁大师进行硬件检测

文章目录简介dxdiag系统信息设备管理器任务管理器PowerShelldxdiag系统信息设备管理器任务管理器PowerShellTODO&#xff1a;CPU-ZTODO&#xff1a;Everest参考文献简介 不少二手电脑重装系统后发现是假配置&#xff08;特别是XP系统&#xff09;&#xff0c;可以使用系统自带…

基于Vue2实现滚动过程中数据懒加载

以下为实现滚动懒加载的过程&#xff1a; 1、在data对象中定义了items数组&#xff0c;用于存放已加载的item&#xff0c;loading状态&#xff0c;当前页数page&#xff0c;每页数量pageSize&#xff0c;以及距离底部的阈值threshold。 2、在mounted钩子函数中&#xff0c;首次…

Adaptive AUTOSAR——State Management(VRTE 3.0 R21-11)

状态管理是自适应平台服务中的一个功能集群。 在自适应平台中&#xff0c;状态决定了一组活动的自适应应用程序。 特定于项目的应用程序&#xff0c;即状态管理器&#xff0c;决定何时请求状态更改&#xff0c;从而更改当前活动的应用程序集。状态管理器是特定于项目的&#…

【Golang】三分钟让你快速了解Go语言为什么我们需要Go语言?

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: Go语言核心编程近期目标&#xff1a;写好专栏的每一篇文章 目录一、Go语…

Pytorch基础 - 3. torch.utils.tensorboard

目录 1. 简介 2. 基本步骤 3. 示例1 - 可视化单条曲线 4. 示例2 - 可视化多条曲线 5. 示例3 - 可视化网络结构 1. 简介 Tensorboard是Tensorflow的可视化工具&#xff0c;常用来可视化网络的损失函数&#xff0c;网络结构&#xff0c;图像等。后来将Tensorboard集成到了P…

wps如何修改已经存在的目录标题内容?

如需了解更多办公应用的相关知识&#xff0c;可进入到赛效官网查看应用资讯或者应用问答栏目。 在WPS文档中&#xff0c;为方便大家查看文档中的内容&#xff0c;可以给文档内容添加目录&#xff0c;很多人由于对文档功能不太熟悉&#xff0c;所以当目录生成以后&#xff0c;想…

高效又稳定的ChatGPT大模型训练技巧总结,让训练事半功倍!

文&#xff5c;python前言近期&#xff0c;ChatGPT成为了全网热议的话题。ChatGPT是一种基于大规模语言模型技术&#xff08;LLM&#xff0c; large language model&#xff09;实现的人机对话工具。现在主流的大规模语言模型都采用Transformer网络&#xff0c;通过极大规模的数…

Day941.仓库版本管理 -系统重构实战

仓库&版本管理 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于仓库&版本管理的内容。 当代码以及团队达到一定的规模以后&#xff0c;这会给项目仓库和版本的管理带来诸多问题。 一张常见问题的表格&#xff0c;不妨“对号入座”&#xff0c;看看项目有没…

【常见CSS扫盲雪碧图】从源码细看CSS雪碧图原理及实现,千字详解【附源码demo下载】

【写在前面】其实估计很多人都听过雪碧图&#xff0c;或者是CSS-Sprite&#xff0c;在很多门户网站就会经常有用到的&#xff0c;之所有引出雪碧图这个概念还得从前端加载多个图片时候页面闪了一下说起&#xff0c;这样给人的视觉效果体验很差&#xff0c;也就借此机会和大家说…

Linux查看串行端口

查看串口驱动 cat /proc/tty/driver/serial查看串口设备 dmesg | grep ttyS*[rootlocalhost driver]# cat /proc/tty/driver/serial serinfo:1.0 driver revision: 0: uart:16550A port:000003F8 irq:4 tx:0 rx:0 1: uart:16550A port:000002F8 irq:3 tx:0 rx:0 CTS|DSR|CD 2:…

攻防世界-inget(简单的SQL注入、万能密码)

目录 1、手工注入&#xff08;万能密码原理&#xff09; 2、sqlmap实现 3、常用参数 1、手工注入&#xff08;万能密码原理&#xff09; 打开链接&#xff0c;提示输入id并尝试绕过 尝试一下万能密码&#xff0c;使用逻辑语句使结果返回 构造payload /?id or 我们这里是…

Java虚拟机内存区域

Java虚拟机所管理的内存将会包括以下几个运行时数据区域 程序计数器 是一块较小的内存空间&#xff0c;可以看作当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要通过更改这个计数器的值来改变下一条需要执行的字节码。 由于各个线…

DAY 35 sed文本编辑器

文本三剑客&#xff1a;都是按行读取后处理。 grep 过滤行内容 awk 过滤字段 sed 过滤行内容&#xff1b;修改行内容 sed编辑器 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流 sed编辑器可以根据命令来处理数据流中的…

Shell编程(二)

上一章&#xff1a; Shell编程_做测试的喵酱的博客-CSDN博客 七、ping shell脚本&#xff0c;是一个面向过程的编程语言&#xff0c;没有类和对象的概念。用的最多的就是函数。 查看当前服务&#xff0c;是否能ping通baidu ping www.baidu.com [rootecs-39233 dev]# ping ww…

眺望2023:房企“三大护法”如何助力穿越周期?

2022 年的地产行业尤为艰难&#xff0c;土地和商品房成交量明显下滑&#xff0c;许多房企的业绩都呈现收缩态势。 不过&#xff0c;今年以来房地产市场似乎出现企稳信号。国家统计局数据显示&#xff0c;今年1~2月全国商品房销售面积和销售额的下跌幅度明显收窄&#xff0c;住…

18-java单列集合

java单列集合1.集合体系结构1.1 单列集合1.2 双列集合2. 单列集合体系结构3.Collection集合顶层接口3.1 Collection的遍历方法3.1.1 迭代器遍历3.1.2 增强for遍历3.1.3 Lambda表达式4. List单列集合4.1 List4.1.1 List集合特点4.1.2 List集合的特有方法4.1.3 List集合遍历方法4…

计算机组成原理实验三-----系统总线和具有基本输入输出功能的总线接口实验

总线是计算机中连接各个功能部件的纽带&#xff0c;是计算机各部件之间进行信息传输的公共通路。 总线不只是一组简单的信号传输线&#xff0c;它还是一组协议。他有两大特征 分时: 同一总线在同一时刻&#xff0c;只能有一个部件占领总线发送信息&#xff0c;其他部件要发送信…

游戏基础—Android平台进程模块信息获取

记得学习编程时的第一个helloworld程序&#xff1a; #include<stdio.h> Int main(int argc, char **argv) { printf(“Hello World”); return 0; } 打印” Hello World”&#xff0c;使用的是printf函数。但是&#xff0c;我们并没有去实现printf函数的功能&#xff0…