30

Now I have a class User, I get a request data of an array from the jsp or html.

list this Integer[] arr=[5,6,9,10,62,52,21]

and then I use two methods to finish bulking deleting action.

@Transactional
@Override
public void deleteUser(Integer id) {

    oneRepository.delete(id);
}


@Transactional
@Override
public void deleteSomeUser(Integer[] ids) {

    for (Integer id : ids) {

        deleteUser(id);

    }

}

I want to know that if it's a more efficient method to finish this action.

you can see my logs: it seems not so good!

[94, 95, 91, 92, 93]
Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?


Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    delete 
    from
        sshh_user 
    where
        ID=?



Hibernate: 
    select
        count(practice0_.ID) as col_0_0_ 
    from
        sshh_user practice0_
Neil Stockton
  • 11,383
  • 3
  • 34
  • 29
JSO
  • 421
  • 2
  • 7
  • 11

6 Answers6

70

Just add the following to your user repository interface

void deleteByIdIn(List<Integer> ids);

Spring will automatically generate the appropriate query via method name derivation.

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods

EDIT: A litte more detail on this

Using Springs Repository interfaces like CrudRepository, JpaRespository brings the basic set of database operations, like create, read, update, delete, paging, sorting and so on.

To manually add some simple queries like searching for a users name or mail address spring provides a fine mechnanism without annotating any string based HQL queries or similar.

Spring just analyses your method names, searching for keywords. Read the documentation link above which keywords are provided.

Example methods for a CrudRepository<User>:

Iterable<User> findByNameLike(String search) resolves to select * from user where name like '<search>'

void deleteByIdIn(List<Integer> ids) resolves to delete from user where id in ([ids])

UPDATE:

This will only work as a real bulk delete in Spring Boot Version < 2.0 !

Since Spring Boot 2.0 it will result in single delete queries to honour JPA Entity Lifecycle Events like preRemove and postRemove.

If you want to really bulk delete, please use the accepted answer.

LazyProphet
  • 1,184
  • 2
  • 10
  • 9
  • Hello, please add some explanation to the code - for instance, what this does, etc. While providing links to documentation is useful, including that information is beneficial to everyone. – Chait Mar 08 '17 at 14:20
  • Just a word of warning on this solution, due to a bug in Eclipselink this won't work (it generates malformed queries) so you have to fall back to adding a query to the method name if you are using EclipseLink. – PaulNUK May 26 '17 at 08:55
  • 1
    Its working perfectlty with Hibernate so far. Another (and far more flexible) way is to use QueryDSL (http://www.baeldung.com/rest-api-search-language-spring-data-querydsl) – LazyProphet Jun 26 '17 at 12:36
  • 7
    this does not work in version 2.0.5.RELEASE. deleteByIdIn generates as many delete queries as the number of the ids you provide. – Yuriy Kravets May 02 '18 at 16:54
  • 1
    Note that this throws an exception when `ids` is empty. – User1291 Oct 24 '19 at 09:37
  • 1
    Tried deleteByIdIn() and looked into Hibernate debug log, looks like the method translated into multiple delete queries instead of the single query mentioned above. I ended up writing custom query as outlined in the accepted answer. – Yuming Cao May 18 '20 at 01:38
44

Suppose you have a UserRepository like:

public interface UserRepository extends JpaRepository<User, Integer> {}

Then you can add a modifying query method like following into your UserRepository:

/**
 * Delete all user with ids specified in {@code ids} parameter
 * 
 * @param ids List of user ids
 */
@Modifying
@Query("delete from User u where u.id in ?1")
void deleteUsersWithIds(List<Integer> ids);

Finally you can change your bulk deletion service like following:

@Transactional
@Override
public void deleteSomeUser(Integer[] ids) {
    oneRepository.deleteUsersWithIds(Arrays.asList(ids));
}

This will generate a delete query like:

Hibernate: delete from users where id in (? , ? , ?)

Also be aware of Self Invocation issues when you calling one public advised method from another one.

Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
  • Updated link to the Spring documentation about self invocation: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-understanding-aop-proxies – Hein Blöd Aug 01 '18 at 13:39
  • 1
    Note that this will not automatically trigger cascaded deletes on entities in a relationship with the deleted entities, cf. https://stackoverflow.com/questions/23443188/why-does-a-manually-defined-spring-data-jpa-delete-query-not-trigger-cascades – Hein Blöd Aug 01 '18 at 14:02
  • Also note, that there are sql in clause limit. For example, in PostgreSQL https://stackoverflow.com/questions/1009706/postgresql-max-number-of-parameters-in-in-clause – Woland Jan 17 '19 at 08:43
  • 1
    Note taht this throws an exception if `ids` is empty. – User1291 Oct 24 '19 at 09:36
  • This worked for me! However shouldn't Spring data JPA provide this functionality through method ```repository.deleteAll(entinties) ,repository.deleteAllById(ids)``` – Dev Fh Aug 17 '21 at 09:23
  • Could we get an example for people that use composite keys? (We use `@IdClass` on our entities) – payne Oct 27 '21 at 15:17
  • How would this work for composite keys declared via `@IdClass`? (talking about something similar to `@Modifying @Query("delete from User u where u.prop1 and u.prop2 in ?1") void deleteUsersWithIds(List ids);`) – payne Oct 28 '21 at 02:08
  • I created a specific question for that: https://stackoverflow.com/q/69747958/9768291 – payne Oct 28 '21 at 03:44
1

You can use different method for deleteAll item list without call repository twice. When deleteAll method call, CrudRepository or JpaRepository look just objects id.

List<User> userList = userIdList.stream().map(id -> {
            User user = new User();
            user.setId(id);
            return user;
        }).collect(Collectors.toList());

userRepository.deleteAll(userList);
Talha Dilber
  • 117
  • 1
  • 3
1

I have use this function for delete list of elements in JPA repository

void deleteInBatch(List<Integer> list);
Nilupul Heshan
  • 580
  • 1
  • 5
  • 18
0

If your repository interface extends CrudRepository, you can simply use its deleteAll(Iterable<? extends T> var1) method to delete a collection of entities:

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
    
    void deleteAll(List<User> usersToDelete);

}
DimaSan
  • 12,264
  • 11
  • 65
  • 75
xyz777
  • 57
  • 7
  • You should post actual code and mark it as such since the answer is correct. There's a button on top of the editor which creates a code block out of your highlighted text. – G_V May 19 '20 at 13:43
  • He's working with Primary Keys, though. This answer assumes that he's working with entities, or will construct some entities using the PKs. – payne Oct 27 '21 at 14:58
  • Author wanted to avoid separate Hibernate queries. `deleteAll` and `deleteAllById` seem to not solve this as per my test they still make separate queries. The solution from the accepted answer performed as described. – syydi Mar 18 '22 at 07:38
0

Thanks rayrayj92 for the solution. You don't need to write any custom query, just get a list of Objects and delete all objects by that list.

@DeleteMapping("/deleteproduct")
public ResponseEntity<?> deleteProduct(@Valid @RequestBody Map<String,Object> userMap){

    List<String> idList=(List<String>) userMap.get("id_list");

    List<Product> productList=(List<Product>) productRepository.findAllById(idList);
    productRepository.deleteAll(productList);
    return ResponseEntity.status(HttpStatus.OK).body("Deleted item : "+productList);

}
Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
megasubhash
  • 109
  • 4