There are two ways of going about this - a) Get the object from the db, set the values in java code and use 'save()' to update. b) Run a custom update query
I was hoping to get a definitive answer on what is the standard practice for this and why one would be preferable over the other?
I have tried to find past questions on this topic but wasn't able to find a conclusive answer on which is preferable and why? In a) I can see the extra query as a downside but it feels fairly convenient and readable. In case of b) it seems better because it would be running a single query.
I read up on the middle ground approach of using getOne functionality to fetch proxies/references to the entry so the 'get' query isn't directly executed in the first approach. However, it requires extending a less generic repository and consensus seemed to be to avoid it.
CodePudding user response:
You can use first approach for asking to db "do exist my record in db by id?" - if not then throw error to me. For example,
repository.findById(id).orElseThrow(() -> new NotFoundException("blabla bla not found"));
In any case, without getting by id you can you only repository.save(entity)
where your entity have id and if it's id is in db then your entity will be updated.
I hope that it was shortly but lightly for understanding.
UPD: you can update entity directly using @query @Modify but why? You already have method for save/update Jpa inside. It will be not comfortable to write a query if you have entity with a lot of fields and you not always update similar fields, but you can use mupstruct (for example) jpa and all will be okay :) more clean code
CodePudding user response:
Both options exists because they have there usage and there is even a third option which is a variant of the first option.
The JPA way
The JPA way is how JPA works by default, and it is close to your option a):
- start a transaction which also starts a persistence context.
- load one or more entities.
- change the entities in what ever way you want. This will mark the entities as dirty in your persistence context.
- commit the transaction, which will flush the changes in the persistence context.
This is your variant a) without the call to save
which isn't necessary for JPA.
The DDD/Spring Data way
Spring Data is build around the concept of a repository, which comes from Domain Driven Design.
A repository is similar to a collection, in which you can put entities. Aggregates to be precise, but that is a different story. You put entities into the repository by calling save
or saveAll
.
In most Spring Data modules this call to save is required. Only JPA with its dirty checking mechanism technically doesn't require it when the entity was loaded in the same persistence context.
But leaving it out creates an invisible dependency between your business code interacting with the entity, and the persistence technology used (JPA).
In the opinion of the Spring Data team you should always call save
.
Bypassing JPA
The third alternative is to directly execute an insert or update statement. This really operates on a lower abstraction layer than JPA. You now have to manually make sure that the state in your database is properly represented in the in memory entity, which easily collides with JPAs 1st level cache and dirty checking. You also have to manually maintain constraints like those required by optimistic locking, or auditing. And JPA won't fire any live cycle events.
But it has benefits as well: It is faster. Possibly much faster. You save yourself a database roundtrip. If you update only a few fields, you might save on data pushed to the database. And you can easily update many rows with one statement.
What to pick
At some point in your project you choose (Spring Data) JPA, presumably because its features offer some benefit to you. Therefore I'd use The JPA way or the The DDD/Spring Data way by default.
But if you have performance issues it is worthwhile to remember you can drop to the lower abstraction level of Bypassing JPA.
If you are using that approach a lot, you might want to consider if JPA was the correct choice in the first place or if something else like MyBatis, Jooq, or Spring Data JDBC would be a better choice for you.