Hibernate Envers and Hibernate Auto Flush - java

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.

Related

Is transaction need to be committed to fire a trigger?

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.

Prevent hibernate from flushing on read only operations

I have a heavy operation, which is read only. This is all mapped by hibernate, in a spring boot application.
Hibernate spends 6seconds flushing my entities, when there is no mutation of any sort. This is simply a get operation.
I am trying to stop hibernate from spending that 6 second, flushing redundantly.
I put hibernate flush mode to MANUAL/NEVER. But it didn't make any difference.
The property is set correctly, but hibernate stats still show the flushing, count, and the time spent.
There are several ways to do it. You may try:
org.springframework.transaction.annotation.Transactional annotation set to read-only:
#Transactional(readOnly = true)
Which in case of Hibernate, it sets the JDBC transaction into a read-only mode and FlushMode.NEVER.
Here details: https://stackoverflow.com/a/1712328/5810648
Also, it is possible to disable dirty-check calling setReadOnly(true) on Hibernate query or call setHint("org.hibernate.readOnly", true) on JPA query. According to doc :
Hibernate will never dirty-check them or make changes persistent ( eg.
new Boolean(true) ), default to false
http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1215
Another way is to use stateless session for that heavy operation. Here is details: https://stackoverflow.com/a/5497077/5810648

How to audit in a for-loop (Hibernate envers)?

I am using hibernate envers for auditing.
It works fine but today I realized that it doesnt if I create entities in a for-loop.
After set log true for sql queries I figured out, that the rev-tables are not updated after each iteration. Somehow hibernate collects all changes and fires the audit command in the end of a request? How can I let hibernate to do auditing after each iteration in my for-loop?
What I already tried:
for (...) {
Obj a = new Obj();
objRepository.save(a);
entityManager.flush();
entityManager.clear();
}
As #gtosto points out, Hibernate Envers operates on a transaction boundary basis and therefore audit records won't be flushed and persisted until commit.
One way to synchronize this would be to manually control the transaction boundary yourself as a part of the for-loop so you basically persist small buckets of the list and commit.
The downside here is that can be performance intensive, particularly if the list of objects you're trying to persist is quite large.
The jira issue HHH-9622 outlines a request to make the AuditProcess flushable; however, there are consequences to introducing such behavior that need to be considered.
In fact the problem was that I added the #Transactional annotation to the respective class. Remove it and hibernate will fire the audit commands as soon as you call objRepository.save(a). No need for entity manager.

Log database CUD operations and rollback statements on demand

My application uses Hibernate/Spring/Struts/MySql.
The requirements are:
Log the HQL queries w.r.t user SessionId.
Revert/rollback statements on demand.
Intention is to quickly log the changes user does to data and also revert instantly if needed. I am not sure about the feasibility of such.
Yes, you can. The fist, look at hibernate-envers project. This project helps you to make changes audit. Its creates audit table for every entity table and fills it automatically when entities has been changed. But the second part of task, I suppose, you can do only manually: in audit tables will be stored all entities changes. Then you can simply revert data in entity to the last version.
Transactions are ACID and they are durable. Rolling back a committed transaction is not possible, because there might be other transactions already using the state state you changed.
You probably want a CQRS architecture, where events are stored in the data base (solving the audit logging requirement too) and the changes are replayed by a batch processor.
The easiest way to revert an action is by submitting a compensatory event.

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.

Categories