Spring JPA: Should the Save() method commit data to the database? - java

I am using Spring data for my project, I am using a Standard Repository that extends CRUD Repository.
My code is working as expected, however when I call repository.save() the database is not altered?
Do I also need to then call a commit after this in order to alter the Database? Or should the repository.save() method be altering the database automatically?

When your application runs, the Entity Manager associated with the thread keeps control of modified or added objects, the save() method just do this, it's a mark that says: "this should be saved in the database".
The database DML (insert,update,delete) is not sent to the database while you save things, it's done at the end just before commit, it's delayed to the last moment.
It's possible the send the DML to the database anytime you like using the Entity Manager's flush() method, in fact you can debug the database log and see your queries going through, but this changes to the database will only be visible within your DB connection until the commit is issued; commit() is a method of the transaction associated to the Entity Manager.
In some frameworks like play 1.4.x the commits is issued after the response view is correctly parsed and rendered.

Related

Hibernate Firing Update query on an entity even when there is no property changed

We have spring boot project with JPA hibernate. The setup is very common - RestController - Service - Repository.
There is one particular endpoint with Return type of Entity. The service fetches the entity from db, does some calculation and returns it to the client. The problem is, as soon as the service call returns, an update query is fired on this entity in the back end. None of the entity property is changed. Repository.save() also is not called still update query is being fired. I want to understand this behavior and possibly stop it.
If fetch is all i am doing, I don't want the JPA/Hibernate to fire an update query if save() or saveAndFlush() is not called. its resulting unnecessary load on db.
An entity returned from the database is "managed" in the world of hibernate. So when the transaction block / boundaries close hibernate may issue a save back to the db because it thinks that the entity is dirty and needs to be updated with the in memory / hibernate cache info it has.
I do not think that you can skip this as is part of how hibernate works. Even if you see an update being issued I suggest you do not worry.

JPA flush vs commit

in JPA, if we call EntityTransaction.commit(), does it automatically call EntityManager.flush()? or should we call them both? what is the difference? because i have problem with JPA, when i insert an entity to database, i call persist(). in the database, the data has been inserted (can be fetched), but that data doesn't show up in my app (i fetch it using findAll()). and on another entity, it showed up. is there something i don't know? i'm using standard Spring CRUD, JPA resource_local, and postgresql. sorry for my english, thanks in advance
if we call EntityTransaction.commit(), does it automatically call
EntityManager.flush()?
Yes
what is the difference?
In flush() the changes to the data are reflected in database after encountering flush, but it is still in transaction.flush() MUST be enclosed in a transaction context and you don't have to do it explicitly unless needed (in rare cases), when EntityTransaction.commit() does that for you.
Source
em.flush() - It saves the entity immediately to the database with in a transaction to be used further and it can be rolled back.
em.getTransaction().commit - It marks the end of transaction and saves all the changes with in the transaction into the database and it can't be rolled back.
Refer https://prismoskills.appspot.com/lessons/Hibernate/Chapter_14_-_Flush_vs_Commit.jsp
If you have a #Version annotated column in your entity and call entityManager.flush(), then you will either (immediately!) get an OptimisticLockException, or the database will lock this row (or table). In the later case you can still call setRollbackOnly(), and the lock will later be released without a DB change.
Or from a different perspective, with flush() you can create a (pessimistic) lock on that database row. The others will still see the old entry, but if they try to update they will be blocked, until the lock is released.
All this is also true for CMT (container managed transactions). Instead of waiting for the moment, where the service method is finished and the CMT commit is performed, you can call flush() (even several times) in your service method and handle the OptimisticLockException(s) immediately.

synchronize EntityManager with database

I deleted a record from the database, and the entity manager still references that deleted record.
I have the following query:
List results = em.createNamedQuery("Customers.findNew")
.setParameter("status", "n")
.getResultList();
I am getting back results which include the deleted record. I've read the entity manager caches the database for better performance. This is fine if only the application using the entity manager is accessing the database. But what happens when multiple systems will access the same database?
I have tried:
1. em.flush()
2. em.refresh()
3. em.clear()
right before I use entity manager to query the database, to try and force a re synchronization but none of them do. I am still getting the same record that isn't in the database anymore.
UPDATE
The program I used to delete record, Oracle SQL Developer, didn't commit changes. So JPA was working fine, it was the program I was using to make changes to the database hadn't committed the changes. If you are experiencing similar problem make sure the db admin program committed changes.
EntityManagers cache Objects themselves, for their own use. This is generally save.
In addition, you can enable the 2nd level cache, where inconsistencies can arise between systems. If you enabled this, try to disable it.
Did you delete the entity using the same EntityManager? If no, make sure the transaction to delete the entity is commited and make sure the transaction of your reading EntityManager starts after the deletion is commited.

JPA Entity updating database without persist/merge

Our java application is using Toplink JPA to connect the data access layer to our SQL Server 2008 database.
We can query the database and get our results without any issue. The problem is that if we try and change the returned entity, it persists to the database as soon as the setter is called.
Query rQuery = em.createNamedQuery("Region.findAll");
Region r= rQuery.getResultList();
r.setActive(active);
From what we've been reading on JPA, it seems like it shouldn't send the changes to the database until persist/merge/flush is called. This is the behavior we're looking to have. We want to be able to make all of our changes and then send them all at once. If we send them one at a time and we get an error, we could end up with partially updated records.
I've tried setting the entity manager flush mode to commit in order to force it to wait for a commit call before persisting and it didn't make any difference.
em.setFlushMode(FlushModeType.COMMIT);
I also tried detaching the returned entity before calling the setters, but it throws an exception.
java.lang.AbstractMethodError: oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl.detach(Ljava/lang/Object;)
This is our first time using Toplink JPA and we don't know what else to try.
If anyone has any other suggestions on how to fix this issue I'd really appreciate it.
If your updating code to the entity is done within a method marked with a transaction then by the end of that method changes will be committed since the transaction must commit any changes before it closes.
Merge is used if the entity is detached ,you made some changes to that entity and you need to re-attach it again and merge the update in the database.
The solution is to make the query for data in a different method with transaction attribute 'Require_new' and pass the result set to the method that do the update with transaction attribute 'required' or 'mandatory'.

What does EntityManager.flush do and why do I need to use it?

I have an EJB where I am saving an object to the database. In an example I have seen, once this data is saved (EntityManager.persist) there is a call to EntityManager.flush(); Why do I need to do this? The object I am saving is not attached and not used later in the method. In fact, once saved the method returns and I would expect the resources to be released. (The example code does this on a remove call as well.)
if (somecondition) {
entityManager.persist(unAttachedEntity);
} else {
attachedEntityObject.setId(unAttachedEntity.getId());
}
entityManager.flush();
A call to EntityManager.flush(); will force the data to be persisted in the database immediately as EntityManager.persist() will not (depending on how the EntityManager is configured: FlushModeType (AUTO or COMMIT) by default is set to AUTO and a flush will be done automatically. But if it's set to COMMIT the persistence of the data to the underlying database will be delayed until the transaction is committed.
EntityManager.persist() makes an entity persistent whereas EntityManager.flush() actually runs the query on your database.
So, when you call EntityManager.flush(), queries for inserting/updating/deleting associated entities are executed in the database. Any constraint failures (column width, data types, foreign key) will be known at this time.
The concrete behaviour depends on whether flush-mode is AUTO or COMMIT.
So when you call EntityManager.persist(), it only makes the entity get managed by the EntityManager and adds it (entity instance) to the Persistence Context. An Explicit flush() will make the entity now residing in the Persistence Context to be moved to the database (using a SQL).
Without flush(), this (moving of entity from Persistence Context to the database) will happen when the Transaction to which this Persistence Context is associated is committed.
The EntityManager.flush() operation can be used the write all changes to the database before the transaction is committed. By default JPA does not normally write changes to the database until the transaction is committed. This is normally desirable as it avoids database access, resources and locks until required. It also allows database writes to be ordered, and batched for optimal database access, and to maintain integrity constraints and avoid deadlocks. This means that when you call persist, merge, or remove the database DML INSERT, UPDATE, DELETE is not executed, until commit, or until a flush is triggered.
EntityManager.flush() sends actual SQL commands to DB.
Persistence framework usually manages transactions behind the scene. So there is no guaranty that flushed queries will be successfully committed.
EntityManager.flush() is always called just before the transaction commit by persistence framework automatically behind the scene.
EntityManager.persist() only registers an entity to persistence context without sending any SQL statements to DB. That means you won't get auto generated IDs after persist(). You just pass persisted object and eventually after later flush() it gets ID. You can call flush() yourself to get those IDs earlier. But again it is not the end of transaction so it can be rolled back and even more: changes might be seen (via phantom reads) by other transactions/thread/processes/servers and then disappear depending on DB engine and isolation level of current and foreign transaction!

Categories