Spring JPA学习之delete方法示例详解

目录
  • 一、deleteById 和 delete
    • deleteById(Id id)(通过id进行删除)
    • delete(T entity)(通过实体对象进行删除)
  • 实例
    • service 层
    • control层
  • 二、deleteAllById 和 deleteAll
    • 1、deleteAllById(Iterable<? extends ID> ids)(通过id进行批量删除)
    • 2、deleteAll(Iterable<? extends T> entities)(通过实体对象进行批量删除)
  • 实例
    • service 层
    • control层
  • 三、deleteAllInBatch 和 deleteAllByIdInBatch
    • 1、deleteAllInBatch(Iterable<T> entities)(通过实体对象进行批量删除)
    • 2、deleteAllByIdInBatch(Iterable<ID> ids)源码(通过ids批量删除)
  • 结论:

一、deleteById 和 delete

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

deleteById(Id id)(通过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(T entity)(通过实体对象进行删除)

@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方法(deleteByIdJPA 自带接口不需要在dao层中添加)

@Transactional
public void deleteById(Integer id){
    userDao.deleteById(id);
}

control层

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

执行请求 /deleteById?id=2,控制台打印如下:

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 和 deleteAll

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

@Override
@Transactional
public void deleteAllById(Iterable&lt;? extends ID&gt; ids) {
   Assert.notNull(ids, "Ids must not be null!");
   for (ID id : ids) {
      deleteById(id);
   }
}

结论

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

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

@Override
@Transactional
public void deleteAll(Iterable&lt;? extends T&gt; 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));
}

浏览器测试成功 /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 和 deleteAllByIdInBatch

1、deleteAllInBatch(Iterable<T> 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<T> 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=?

2、deleteAllByIdInBatch(Iterable<ID> 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

结论:

从上面两种删除接口来看,第二种实现比起第一种更加的快捷;

第一种就是一条一条的进行删除操作,如果有万级的数据,执行起来肯定非常耗时,所以如果数据量比较大的话,还是建议大家使用第二种。

以上就是Spring JPA学习之delete方法示例详解的详细内容,更多关于Spring JPA delete方法的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring JPA find单表查询方法示例详解

    目录 一.findById(ID id) 二.findAll() 三.findAllById(Iterable<ID> ids) 四.findAll(Sort sort) 单调排序 sort.by 源码 control层 五.findAll(Sort sort) 多参数排序 Sort by 源码 control 层 总结 一.findById(ID id) 通过id进行单条查询,先看看 findById(ID id) 的源码 @Override public Optional<T>

  • Spring JPA联表查询之注解属性详解

    目录 前言 一.targetEntity 二.cascade 1.不定义 2.CascadeType.PERSIST 3.CascadeType.REMOVE 4.CascadeType.REFRESH 5.CascadeType.MERGE 6.CascadeType.ALL 三.fetch FetchType.LAZY FetchType.EAGER 四.mappedBy 五.orphanRemoval 前言 对于联表查询的四个注解 @OneToOne.@OneToMany.@ManyToO

  • Spring JPA之find拓展方法示例详解

    目录 前言 一.单条件查询 1.精确查询(确定值,例如:=.is) 2.范围查询(一定范围,例如<.<=.>.>=.in.between) a)运算符 b)between c)in 3.模糊查询 a)findByNameLike b)findByNameStartingWith 二.多条件查询 三.关键字 最后总结: 前言 前两篇我们详细了解了 findById 和 findAll 以及 findAll 的分页查询,如果说JPA只有上面的两种查询功能,那就太low了,今天让我们再深

  • Spring JPA联表查询之OneToOne源码详解

    目录 前言 源码 注解属性 单向联表 user 实体类 car 实体类 查询结果 双向联表 user 实体 car 实体 查询结果 延迟加载(懒加载) user 实体 查询结果: 查询完会发现,控制台又打印了一个 JPQL: 最后结论 前言 前面几篇我们学习的都是单表查询,就是对一张表中的数据进行查询.而实际项目中,基本都会有多张表联合查询的情况,今天我们就来了解下JPA的联表查询是如做的. 源码 @OneToOne 注解实现一对一关系映射.比如用户跟车辆的关系(这里假设一个人只能有一辆车),一

  • Spring JPA之save方法示例详解

    目录 一.save(单条添加) 源码 service 层 control层 二.saveAll(批量添加) 源码 service control层 一.save(单条添加) 源码 @Transactional @Override public <S extends T> S save(S entity) { Assert.notNull(entity, "Entity must not be null."); if (entityInformation.isNew(enti

  • Spring JPA联表查询之OneToMany源码解析

    目录 前言 源码 单向联表 user 实体类 house 实体类 查询结果 双向联表 user 实体类 house 实体类 对象获取 前言 我们在实际项目中,除了会碰到一对一的情况,还有一对多的情况,比如一个用户可以有多辆车,而一辆车只能有一个用户等等,今天我们就来一起学习下 OneToMany(一对多). 源码 @OneToMany 注解实现一对多关系映射.比如用户跟房子的关系, 一个用户可以有好多房子,而一个房子只能一个用户.老规矩,实例之前先看看源码: public @interface

  • Spring JPA find分页示例详解

    目录 前言 源码 一.单纯分页查询 查询结果 结论 二.排序分页查询 查询结果 三.方法整理 总结: 前言 在现实项目中,数据量一般都不小,如果一次性全部请求出来,肯定是影响性能,而且大量数据展示到页面上观感也不好.这时我们就需要用到分页,给定一个 pageSize,每次请求的数量就是 pageSize 的大小,这样既可以节约时间,又可以美化页面.Spring JPA 就为我们提供这样一个方法,准确来说是提供了一个对象用来约束数据按照分页的形式进行请求. 源码 findAll(Pageable

  • 人工智能学习Pytorch张量数据类型示例详解

    目录 1.python 和 pytorch的数据类型区别 2.张量 ①一维张量 ②二维张量 ③3维张量 ④4维张量 1.python 和 pytorch的数据类型区别 在PyTorch中无法展示字符串,因此表达字符串,需要将其转换成编码的类型,比如one_hot,word2vec等. 2.张量 在python中,会有标量,向量,矩阵等的区分.但在PyTorch中,这些统称为张量tensor,只是维度不同而已. 标量就是0维张量,只有一个数字,没有维度. 向量就是1维张量,是有顺序的数字,但没有"

  • Python学习之模块化程序设计示例详解

    目录 关于模块化程序设计 水果仓库功能简介 主功能实现与程序入口 实现添加功能 实现列出所有信息功能 实现查询信息功能 实现删除信息功能 完整程序如下 关于模块化程序设计 什么是模块化程序设计? 程序设计的模块化指的是在进行程序设计时,把一个大的程序功能划分为若干个小的程序模块.每一个小程序模块实现一个确定的功能,并且在这些小程序模块实现的功能之间建立必要的联系,通过各个小模块之间的互相协作完成整个大功能实现的方法. 模块化设计程序的方法? 一般在针对实现比较复杂程序的情况下,采用的是自上而下的

  • Go语言中的字符串处理方法示例详解

    1 概述 字符串,string,一串固定长度的字符连接起来的字符集合.Go语言的字符串是使用UTF-8编码的.UTF-8是Unicode的实现方式之一. Go语言原生支持字符串.使用双引号("")或反引号(``)定义. 双引号:"", 用于单行字符串. 反引号:``,用于定义多行字符串,内部会原样解析. 示例: // 单行 "心有猛虎,细嗅蔷薇" // 多行 ` 大风歌 大风起兮云飞扬. 威加海内兮归故乡. 安得猛士兮守四方! ` 字符串支持转义

  • 编译安装redisd的方法示例详解

    安装方法: yum安装 查看yum仓库redis版本 [root@centos ~]# yum list redis Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Available Packages redis.x86_64 3.2.12-2.el7 myepel yum安装 [root@centos ~]# yum install redis -y 启动服务并设为开机启动

  • VSCode各语言运行环境配置方法示例详解

    系统环境变量的配置 如:将F:\mingw64\bin添加到系统环境变量Path中 VSCode软件语言json配置C语言 创建个.vscode文件夹,文件夹内创建以下两个文件 launch.json 文件配置 { "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch", "type": "cppdbg&

  • 浅谈使用Java Web获取客户端真实IP的方法示例详解

    Java-Web获取客户端真实IP: 发生的场景:服务器端接收客户端请求的时候,一般需要进行签名验证,客户端IP限定等情况,在进行客户端IP限定的时候,需要首先获取该真实的IP. 一般分为两种情况: 方式一.客户端未经过代理,直接访问服务器端(nginx,squid,haproxy): 方式二.客户端通过多级代理,最终到达服务器端(nginx,squid,haproxy): 客户端请求信息都包含在HttpServletRequest中,可以通过方法getRemoteAddr()获得该客户端IP.

  • PHP基于phpqrcode类生成二维码的方法示例详解

    HP QR Code是一个PHP二维码生成类库,利用它可以轻松生成二维码,官网提供了下载和多个演示demo,查看地址: http://phpqrcode.sourceforge.net/ 下载官网提供的类库后,只需要使用phpqrcode.php就可以生成二维码了,当然您的PHP环境必须开启支持GD2. phpqrcode.php提供了一个关键的png()方法,其中 参数$text表示生成二位的的信息文本: 参数$outfile表示是否输出二维码图片 文件,默认否: 参数$level表示容错率,

  • Python面向对象编程repr方法示例详解

    目录 为什么要讲 __repr__ 重写 __repr__ 方法 str() 和 repr() 的区别 为什么要讲 __repr__ 在 Python 中,直接 print 一个实例对象,默认是输出这个对象由哪个类创建的对象,以及在内存中的地址(十六进制表示) 假设在开发调试过程中,希望使用 print 实例对象时,输出自定义内容,就可以用 __repr__ 方法了 或者通过 repr() 调用对象也会返回 __repr__ 方法返回的值 是不是似曾相识....没错..和 __str__ 一样的

随机推荐