Description
Spring JPA's CrudRepository
interface contains a deleteById
method with the following documentation:
/**
* Deletes the entity with the given id.
* <p>
* If the entity is not found in the persistence store it is silently ignored.
*
* @param id must not be {@literal null}.
* @throws IllegalArgumentException in case the given {@literal id} is {@literal null}
*/
void deleteById(ID id);
The second sentence is correct but can be easily misinterpreted. When looking at the method signature, one could assume that this method just deletes the corresponding entity on the database by id (equivalent to the JPQL query delete from X where id = :id
). And if no entry with that identifier exists, it just ignores the call.
However, when the deleteById method is called in a transactional context concurrently, it can fail with an optimistic lock exception. The reason being that the underlying SimpleJpaRepository
that implements that interface method is actually doing this:
findById(id).ifPresent(this::delete);
It first loads the entity from the db into the persistence context and then deletes the entity instance if found. If a concurrent thread deletes or modifies the same entity between the find and the delete call, the operation will fail. This behavior is not obvious from reading the JavaDoc on the deleteById
method. Could you please improve the documentation there? Or maybe improve the implementation and not load the entity from the db if not already within the current persistence context? Thanks!