Is transaction need to be committed to fire a trigger? - java

In my application, I am updating a table through Hibernate and there is a UPDATE trigger for that table.
My question is, Do I need to commit that transaction(Spring Transaction) under which this update operation is happening ,
to get the trigger fired ?
I am using Spring transaction and Oracle database
Thanks.

Yes, the database level triggers are fired when the data reaches the disk. That only happens when a commit is done.

No, but Hibernate often waits for transaction to end to run all SQL updates, so it may look that way.
Try flushing your changes using EntityManager#flush (JPA api) or JpaRepository#flush (from Spring Data) or using JpaRepository#saveAndFlush after updating entity.

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.

Hibernate Envers and Hibernate Auto Flush

I've got a Spring application using Hibernate. I've implemented Envers into it, which is working fine. However, Hibernate will by default automatically flush before some transactions are committed.
For example, I have an MVC endpoint that will update a record, but before saving it, will have to make various other queries to retrieve some other data. Each time another query is run, Hibernate flushes and this results in there being multiple audit rows for each change. This creates some confusion, as there is already a modified date on my record which isn't changed in each update (as it's flushing before this property is changed).
What are my options for managing this more effectively, and creating a reliable audit log even with Hibernate flushing in this way? Is the only answer to implement my own listener with some custom logic to check if it should actually be committing an audit change or not?
You can detach the entity and merge when you are done. These queries are only executed if they touch tables that would be affected by pending inserts/updates/deletes. If you use native queries, this is a different topic. Hibernate has no SQL parser to figure out which tables you are touching so it is conservative and flushes all pending changes.

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.

Eclipselink/JPA persist a record once or insert each field separately?

I have a question about persist and merge strategy of eclipselink. I would like to know how eclipselink/JPA inserts and updates records. Is it insert/update one by one into database? or it is saving them in a log file and then flush them to the database?
It is important for me, because I am going to have a history table with trigger that triggs when insertion and update. so if for example update is happening on each field, and 3 fields are updated, then I will have 3 records in history table or one?
I will be appreciated if anyone answers me and also leave some reference link for further information.
The persistence provider is quite free to flush changes whenever it sees fit. So you cannot reliably predict the number of update callbacks or the expected SQL statements.
In general, the provider will flush changes before each query to make changes in the persistence context available to the query. You can hint the provider to defer the flush until commit time, but the provider still can flush at will.
Please see the relevant chapters of the JPA (2.0) spec:
§3.2.4 Synchronization to the Database
§3.8.7 Queries and Flush Mode
EDIT: There is an important point to flushing and transaction isolation. The changes are flushed to the database and the lifecycle listeners are invoked, but the data is not committed and not visible to other transactions - the read-committed isolation is the default. The commit itself is atomic.
I am not sure what the consequences of a server crash would be, but under normal circumstances, data integrity is ensured.

Does a Hibernate transaction rollback delete "session.flush()"ed entities?

I have been confused about transaction.rollback. Here is example pseudocode:
transaction = session.beginTransaction()
EntityA a = new EntityA();
session.save(a);
session.flush();
transaction.rollback();
What happens when this code works? Do I have the entity in the database or not?
Short answer: No, you won't have entity in the database.
Longer answer: hibernate is smart enough not to send insert/updates to the DB until it knows if the transaction is going to be committed or rolled back (although this behavior can be changed by setting a different FlushMode), in your case by calling flush you are forcing the SQL to be sent to the DB but you still have the DB transaction to protect you, when you call rollback the DB transaction will be rolled back removing the changes performed inside itself and hence nothing will be actually saved. Note that depending on your configured transaction isolation level perhaps other transactions will be able to see in some way the EntityA you saved for the short while between the save and the rollback.
Also note that flush is called automatically when you try to read from DB, in 99% of the cases calling it explicitly is not necessary. One exception that comes to mind is when unit testing with auto rolling back tests.
When you call session.save(a) Hibernate basically remembers somewhere inside session that this object has to be saved. It can decide if he wants to issue INSERT INTO... immediately, some time later or on commit. This is a performance improvement, allowing Hibernate to batch inserts or avoid them if transaction is rolled back.
When you call session.flush(), Hibernate is forced to issue INSERT INTO... against the database. The entity is stored in the database, but not yet commited. Depending on transaction isolation level it won't be seen by other running transactions. But now the database knows about the record.
When you call transaction.rollback(), Hibernate rolls-back the database transaction. Database handles rollback, thus removing newly created object.
Now consider the scenario without flush(). First of all, you never touch the database so the performance is better and rollback is basically a no-op. On the other hand if transaction isolation level is READ UNCOMMITTED, other transactions can see inserted record even before commit/rollback. Without flush() this won't happen, unless Hibernate does not decide to flush() implicitly.
I think you get confused with flush and commit.
flush() synchronizes the state with the database, but it is not doing a commit. The state is still visible by transaction, so that you can call rollback to rollback.
So the answer to your question is: no, you don't have the entity (a) in the database.

Categories