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.
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.
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.
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.
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.
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".
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; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With