当前位置:   article > 正文

Springboot + MySQL+ JPA Ⅲ delete方法详解_entity must not be null

entity must not be null

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

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

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

  1. @Transactional
  2. @Override
  3. public void deleteById(ID id) {
  4. Assert.notNull(id, ID_MUST_NOT_BE_NULL);
  5. delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
  6. String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
  7. }
  8. 复制代码

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

  1. @Override
  2. @Transactional
  3. @SuppressWarnings("unchecked")
  4. public void delete(T entity) {
  5. Assert.notNull(entity, "Entity must not be null!");
  6. if (entityInformation.isNew(entity)) {
  7. return;
  8. }
  9. Class<?> type = ProxyUtils.getUserClass(entity);
  10. T existing = (T) em.find(type, entityInformation.getId(entity));
  11. // if the entity to be deleted doesn't exist, delete is a NOOP
  12. if (existing == null) {
  13. return;
  14. }
  15. em.remove(em.contains(entity) ? entity : em.merge(entity));
  16. }
  17. 复制代码

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

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

  1. @Transactional
  2. public void deleteById(Integer id){
  3. userDao.deleteById(id);
  4. }
  5. 复制代码

control层

  1. /**
  2. * 通过id进行删除数据
  3. * @param id
  4. */
  5. @GetMapping("/deleteById")
  6. public void deleteById(Integer id){
  7. userService.deleteById(id);
  8. }
  9. 复制代码

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


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

  1. 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=?
  2. Hibernate: delete from user where id=?
  3. 复制代码

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

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

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

  1. @Override
  2. @Transactional
  3. public void deleteAllById(Iterable<? extends ID> ids) {
  4. Assert.notNull(ids, "Ids must not be null!");
  5. for (ID id : ids) {
  6. deleteById(id);
  7. }
  8. }
  9. 复制代码

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

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

  1. @Override
  2. @Transactional
  3. public void deleteAll(Iterable<? extends T> entities) {
  4. Assert.notNull(entities, "Entities must not be null!");
  5. for (T entity : entities) {
  6. delete(entity);
  7. }
  8. }
  9. 复制代码

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

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

  1. @Override
  2. @Transactional
  3. public void deleteAll() {
  4. for (T element : findAll()) {
  5. delete(element);
  6. }
  7. }
  8. 复制代码

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

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

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

  1. @Transactional
  2. public void deleteAllById(Iterable ids){
  3. userDao.deleteAllById(ids);
  4. }
  5. 复制代码

control层

  1. /**
  2. * 通过id进行批量删除
  3. * @param ids
  4. */
  5. @GetMapping("/deleteAllById")
  6. public void deleteAllById(Integer[] ids){
  7. userService.deleteAllById(Arrays.asList(ids));
  8. }
  9. 复制代码

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


删除后:

控制台打印如下:

  1. 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=?
  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=?
  3. Hibernate: delete from user where id=?
  4. Hibernate: delete from user where id=?
  5. 复制代码

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

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

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

  1. public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
  2. @Override
  3. @Transactional
  4. public void deleteAllInBatch(Iterable<T> entities) {
  5. Assert.notNull(entities, "Entities must not be null!");
  6. if (!entities.iterator().hasNext()) {
  7. return;
  8. }
  9. applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
  10. .executeUpdate();
  11. }
  12. 复制代码
  1. /**
  2. * Creates a where-clause referencing the given entities and appends it to the given query string. Binds the given
  3. * entities to the query.
  4. *
  5. * @param <T> type of the entities.
  6. * @param queryString must not be {@literal null}.
  7. * @param entities must not be {@literal null}.
  8. * @param entityManager must not be {@literal null}.
  9. * @return Guaranteed to be not {@literal null}.
  10. */
  11. public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
  12. Assert.notNull(queryString, "Querystring must not be null!");
  13. Assert.notNull(entities, "Iterable of entities must not be null!");
  14. Assert.notNull(entityManager, "EntityManager must not be null!");
  15. Iterator<T> iterator = entities.iterator();
  16. if (!iterator.hasNext()) {
  17. return entityManager.createQuery(queryString);
  18. }
  19. String alias = detectAlias(queryString);
  20. StringBuilder builder = new StringBuilder(queryString);
  21. builder.append(" where");
  22. int i = 0;
  23. while (iterator.hasNext()) {
  24. iterator.next();
  25. builder.append(String.format(" %s = ?%d", alias, ++i));
  26. if (iterator.hasNext()) {
  27. builder.append(" or");
  28. }
  29. }
  30. Query query = entityManager.createQuery(builder.toString());
  31. iterator = entities.iterator();
  32. i = 0;
  33. while (iterator.hasNext()) {
  34. query.setParameter(++i, iterator.next());
  35. }
  36. return query;
  37. }
  38. 复制代码

通过上面的源码,我们大体能猜测出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
控制台打印如下:

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

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

  1. public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where %s in :ids";
  2. @Override
  3. @Transactional
  4. public void deleteAllByIdInBatch(Iterable<ID> ids) {
  5. Assert.notNull(ids, "Ids must not be null!");
  6. if (!ids.iterator().hasNext()) {
  7. return;
  8. }
  9. if (entityInformation.hasCompositeId()) {
  10. List<T> entities = new ArrayList<>();
  11. // generate entity (proxies) without accessing the database.
  12. ids.forEach(id -> entities.add(getReferenceById(id)));
  13. deleteAllInBatch(entities);
  14. } else {
  15. String queryString = String.format(DELETE_ALL_QUERY_BY_ID_STRING, entityInformation.getEntityName(),
  16. entityInformation.getIdAttribute().getName());
  17. Query query = em.createQuery(queryString);
  18. /**
  19. * Some JPA providers require {@code ids} to be a {@link Collection} so we must convert if it's not already.
  20. */
  21. if (Collection.class.isInstance(ids)) {
  22. query.setParameter("ids", ids);
  23. } else {
  24. Collection<ID> idsCollection = StreamSupport.stream(ids.spliterator(), false)
  25. .collect(Collectors.toCollection(ArrayList::new));
  26. query.setParameter("ids", idsCollection);
  27. }
  28. query.executeUpdate();
  29. }
  30. }
  31. 复制代码

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

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

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

  1. @Override
  2. @Transactional
  3. public void deleteAllInBatch() {
  4. em.createQuery(getDeleteAllQueryString()).executeUpdate();
  5. }
  6. public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
  7. private String getDeleteAllQueryString() {
  8. return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName());
  9. }
  10. 复制代码

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

最终结论:

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56003
推荐阅读
相关标签
  

闽ICP备14008679号