Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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().

like image 440
wisdom_of_wombats Avatar asked Dec 31 '14 08:12

wisdom_of_wombats


People also ask

How do I stop Spring data JPA from doing a select before a save ()?

The solution is to use @javax. persistence. Version on a new versionNumber column in all the tables. If you have a parent and child table then use @Version column in all the entity classes.

Which is better CrudRepository or JpaRepository?

Crud Repository doesn't provide methods for implementing pagination and sorting. JpaRepository ties your repositories to the JPA persistence technology so it should be avoided. We should use CrudRepository or PagingAndSortingRepository depending on whether you need sorting and paging or not.

Is JpaRepository deprecated?

Method Summary Deletes the given entities in a batch which means it will create a single query. Deprecated.

When should I use saveAndFlush and save?

Save and saveAndFlush both can be used for saving entities. They both are both belong to the Spring data library. save may or may not write your changes to the DB straight away. When we call saveAndFlush system are enforcing the synchronization of your model state with the DB.


1 Answers

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.

like image 150
miljanm Avatar answered Sep 17 '22 16:09

miljanm