Spring JpaRepository: delete() with subsequent save() in the same transaction

21,102

Because repository.flush() flushes the changes to the database by calling EntityManager.flush(). So when you flush the changes after delete(), sql gets executed and the following save will have no problems.

If you don't call flush it is up to persistence provider to determine when to flush the changes with transaction commit time being the deadline. Also providers don't flush changes in any particular order, so it may happen that sometimes your operation succeeds and sometimes it doesn't. Usually, providers wait until the commit time flush, but you can influence that by setting a flush mode:

for entitymanager
EntityManager.setFlushMode(FlushModeType type);

or for query
Query.setFlushMode(FlushModeType type);

There is an equivalent setting in Spring data JPA also, I'm sure, but I don't exactly know which one it is.

Note however, that immediately flushing the changes reduces the performance, so you should be careful when using it. In your particular case it is better to update the entity then it is to delete it and then persist the new one with the same business key.

Share:
21,102
wisdom_of_wombats
Author by

wisdom_of_wombats

Updated on December 31, 2020

Comments

  • wisdom_of_wombats
    wisdom_of_wombats over 3 years

    My entity has both autogenerated primary key (id) and business key (namespace). I need to update the record by replacing the old one. So, I'm searching it by business key, delete it and save a new entity. This works if each operation in it's own transaction. But once I put all of them in the same transaction, by the time save() is executed, delete() wasn't executed yet, so I get a constraint violation.

    transactionTemplate.execute(status -> {
        MyEntity oldEntity = repository.findByNamespace(namespace);
        if (oldEntity != null) {
            repository.delete(oldEntity);
        }
        repository.save(newEntity);
        return null;
    });
    

    I actually managed to bypass it by adding

    repository.flush();
    

    But I don't really get why do I need this flush().