Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I stop spring data JPA from doing a SELECT before a save()?

We are writing a new app against an existing database. I'm using Spring Data JPA, and simply doing a

MyRepository.save()  

on my new entity, using

MyRepository extends CrudRepository<MyThing, String> 

I've noticed in the logs that hibernate is doing a Select before the insert, and that they are taking a long time, even when using the indexes.

I've searched for this here, and the answers I've found usually are related to Hibernate specifically. I'm pretty new to JPA and it seems like JPA and Hibernate are pretty closely intertwined, at least when using it within the context of Spring Data. The linked answers suggest using Hibernate persist(), or somehow using a session, possibly from an entityManager? I haven't had to do anything with sessions or entityManagers, or any Hibernate API directly. So far I've gotten simple inserts done with save() and a couple @Query in my Repositories.

like image 240
user26270 Avatar asked Aug 11 '17 12:08

user26270


People also ask

How JPA save method works?

save(…) -Method. It will persist or merge the given entity using the underlying JPA EntityManager . If the entity has not been persisted yet Spring Data JPA will save the entity via a call to the entityManager.

What is the difference between save and saveAndFlush in JPA?

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.

Does Save update JPA?

You can choose between JPA's persist and merge and Hibernate's save and update methods. It seems like there are 2 pairs of 2 methods that do the same. You can use the methods persist and save to store a new entity and the methods merge and update to store the changes of a detached entity in the database.

How can we save entity in JPA without primary key?

Sometimes your object or table has no primary key. The best solution in this case is normally to add a generated id to the object and table. If you do not have this option, sometimes there is a column or set of columns in the table that make up a unique value. You can use this unique set of columns as your id in JPA.


Video Answer


2 Answers

Here is the code of Spring SimpleJpaRepository you are using by using Spring Data repository:

@Transactional public <S extends T> S save(S entity) {      if (entityInformation.isNew(entity)) {         em.persist(entity);         return entity;     } else {         return em.merge(entity);     } } 

It does the following:

By default Spring Data JPA inspects the identifier property of the given entity. If the identifier property is null, then the entity will be assumed as new, otherwise as not new.

Link to Spring Data documentation

And so if one of your entity has an ID field not null, Spring will make Hibernate do an update (and so a SELECT before).

You can override this behavior by the 2 ways listed in the same documentation. An easy way is to make your Entity implements Persistable (instead of Serializable), which will make you implement the method "isNew".

like image 150
Bertrand88 Avatar answered Sep 19 '22 11:09

Bertrand88


If you provide your own id value then Spring Data will assume that you need to check the DB for a duplicate key (hence the select+insert).

Better practice is to use an id generator, like this:

@Entity public class MyThing {     @Id     @GeneratedValue(generator = "uuid2")     @GenericGenerator(name = "uuid2", strategy = "uuid2")     private UUID id; } 

If you really must insert your own id and want to prevent the select+insert then implement Persistable, e.g.

@Entity public class MyThing implements Persistable<UUID> {      @Id     private UUID id;      @Override     public UUID getId() {         return id;     }      //prevent Spring Data doing a select-before-insert - this particular entity is never updated     @Override     public boolean isNew() {         return true;     } } 
like image 31
Paul Hilliar Avatar answered Sep 20 '22 11:09

Paul Hilliar