Spring Data JPA over @SoftDelete (boolean strategy), H2, Hibernate 7.4.14.Final == save, count, deleteById, findById -- count() sql> select count(*) from article_deleted ad1_0 where ad1_0.deleted=false -- deleteById(1) sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? sql> update article_deleted set deleted=true where id=? and deleted=false -- findById(1) sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? isPresent = false -- existsById(1) sql> select count(*) from article_deleted ad1_0 where ad1_0.id=? and ad1_0.deleted=false existsById = false -- count() and findAll().size() sql> select count(*) from article_deleted ad1_0 where ad1_0.deleted=false sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false count = 2, findAll = 2 == derived queries and derived deletes -- countByTitle("x") sql> select count(ad1_0.id) from article_deleted ad1_0 where ad1_0.title=? and ad1_0.deleted=false countByTitle(x) = 1 -- deleteByTitle("x") sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.title=? and ad1_0.deleted=false sql> update article_deleted set deleted=true where id=? and deleted=false returned 1 == deleting something that is already (soft) deleted -- deleteById(1) again sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? no exception -- delete(staleEntity) with the instance saved earlier sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? no exception == save() of a detached instance whose row is soft-deleted -- save(saved.get(0)) sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? result: ObjectOptimisticLockingFailureException -> StaleObjectStateException: Row was already updated or deleted by another transaction for entity [com.ankurm.softdelete.ArticleDeleted with id '1'] == bulk delete, native queries, restore -- @Query("delete from ArticleDeleted a where a.title = :title") bulkDeleteByTitle("z") sql> update article_deleted ad1_0 set deleted=true where ad1_0.title=? and ad1_0.deleted=false returned 1 -- count() vs native count(*) sql> select count(*) from article_deleted ad1_0 where ad1_0.deleted=false sql> select count(*) from article_deleted count() = 1, countIncludingDeleted() = 4 -- native findEvenIfDeleted(1) sql> select * from article_deleted where id = ? present = true -- native restore(1) sql> update article_deleted set deleted = false where id = ? rows updated: 1 -- findById(1) after restore sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false and ad1_0.id=? isPresent = true == deleteAll variants -- deleteAllInBatch() sql> update article_deleted ad1_0 set deleted=true where ad1_0.deleted=false count() = 0, countIncludingDeleted() = 4 -- deleteAll() sql> select ad1_0.id,ad1_0.title from article_deleted ad1_0 where ad1_0.deleted=false sql> update article_deleted set deleted=true where id=? and deleted=false count() = 0