My Application uses FlushMode.AUTO .
For a particular service method call I want to change Hibernate Session.FlushMode to FlushMode.COMMIT and revert back to FlushMode.AUTO when the method completes.
Question:- Are there any problem/dangers of changing FlushMode during the session?
Reason for changing FlushMode during a session:-
I am using Hibernate Interceptor Approach (onFlushDirty) for auditing changes.
With FlushMode.AUTO ,Multiple Session Flushes are occuring(behaviour of FlushMode.AUTO) . So consequently onFlushDirty is being invoked multiple times leading to duplicate audit.
I workaround above issue by changing FlushMode to COMMIT in the method where i am expecting auditing to happen.
The most common reason for triggering an auto flush is when use execute a query during the course of your execution. If Hibernate detects that some of your non-flushed changes in your session could affect the outcome of your query, then it automatically triggers a flush. So when your query executes it gets data that is consistent with the changes you have made in the session.
So, it depends on what your code does. If this behavior does not impact the functionality then it should be ok.
Related
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.
In our application we have a PostDeleteEventListener registered that is executed for each deleted owning entity and possibly for related entities (if cascading delete is enabled).
The listener is used to inspect each entity for a certain property that represents the ID of an entity that is located in one big centralised table without foreign key relation.
The discovered ID's are stored in a java.util.Set held by a ThreadLocal.
What we're looking for is some 'transaction hook' to trigger one delete statement (for performance reasons) with all the ID's held by the java.util.Set.
We tried to achieve this by using a Spring aspect that is executed after a #Transactional method has run. The aspect could then fire the delete statement and clear the java.util.Set.
Unfortunately, it seems that the PostDeleteEventListener is executed AFTER the aspect is triggered. In other words, it gets executed in a separate transaction which I can clearly see by inspecting the stacktrace while debugging. So having an aspect for this doesn't look the way to go...
An other option seems to have a second listener (FlushEventListener) that is executed when the session is flushed.
Although this works, we don't know if this is a good solution?
Are there any other (and better) alternatives out there we can use for this issue?
Is there an other way (Spring or Hibernate) to get notified just before the transaction is committed?
I have some bean method that causes undesired updates to database.
I execute only select statements and recalculate value of some field for my needs, but do not want it to be updated automatically.
How can I control this process without intervention to the default application settings?
Log file says about some mystical background flush process:
begin unit of work flush
Execute query UpdateObjectQuery ...
I can avoid this updates making em.setFlushMode(FlushModeType.COMMIT); in my method. And that is really strange on my machine this works Ok - no updates during method executions and after. But on client machine I also need revert transaction - only in this case I do not see any update statements in my log. But is this cure method correct? Will other threads perform autocommits when I change FlushMode for EM in my bean method?
My machine (GlassFish 2.0, Ubuntu 12.10, eclipcelink 3.2, jdk 1.7.0_15)
Client machine (GlassFish 2.0, Win 7 x86_64, eclipcelink 3.2, jdk 1.7.0_15)
If you want the objects but don't want changes to be persisted, you need to detach it from the EntityManager using em.detach(entity) if using JPA 2.0 or em.clear() if you want everything removed. Rolling back the transaction is pretty much the same as clearing or closing the EntityManager. Detached entities will only have changes persisted if you merge them back into the EntityManager.
You also can do reads outside a transaction if not using JTA. If the EM is not associated to a transaction, changes cannot get flushed. In this way, you can use an EM that is not associated to a transaction and just discard the EntityManager when done.
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.
We are using Hibernate Spring MVC with OpenSessionInView filter.
Here is a problem we are running into (pseudo code)
transaction 1
load object foo
transaction 1 end
update foo's properties (not calling session.save or session.update but only foo's setters)
validate foo (using hibernate validator)
if validation fails ?
go back to edit screen
transaction 2 (read only)
load form backing objects from db
transaction 2 end
go to view
else
transaction 3
session.update(foo)
transaction 3 end
the problem we have is if the validation fails
foo is marked "dirty" in the hibernate session (since we use OpenSessionInView we only have one session throughout the http request), when we load the form backing objects (like a list of some entities using an HQL query), hibernate before performing the query checks if there are dirty objects in the session, it sees that foo is and flushes it, when transaction 2 is committed the updates are written to the database.
The problem is that even though it is a read only transaction and even though foo wasn't updated in transaction 2 hibernate doesn't have knowledge of which object was updated in which transaction and doesn't flush only objects from that transaction.
Any suggestions? did somebody ran into similar problem before
Update: this post sheds some more light on the problem: http://brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/
You can run a get on foo to put it into the hibernate session, and then replace it with the object you created elsewhere. But for this to work, you have to know all the ids for your objects so that the ids will look correct to Hibernate.
There are a couple of options here. First is that you don't actually need transaction 2 since the session is open you could just load the backing objects from the db, thus avoiding the dirty check on the session. The other option is to evict foo from the session after it is retrieved and later use session.merge() to reattach it when you what your changes to be stored.
With hibernate it is important to understand what exactly is going on under the covers. At every commit boundary it will attempt to flush all changes to objects in the current session regardless of whether or not the changes where made in the current transaction or any transaction at all for that matter. This is way you don't actually need to call session.update() for any object that is already in the session.
Hope this helps
There is a design issue here. Do you think an ORM is a transparent abstraction of your datastore, or do you think it's a set of data manipulation libraries? I would say that Hibernate is the former. Its whole reason for existing is to remove the distinction between your in-memory object state and your database state. It does provide low-level mechanisms to allow you to pry the two apart and deal with them separately, but by doing so you're removing a lot of Hibernate's value.
So very simply - Hibernate = your database. If you don't want something persisted, don't change your persistent objects.
Validate your data before you update your domain objects. By all means validate domain objects as well, but that's a last line of defense. If you do get a validation error on a persistent object, don't swallow the exception. Unless you prevent it, Hibernate will do the right thing, which is to close the session there and then.
What about using Session.clear() and/or Session.evict()?
What about setting singleSession=false on the filter? That might put your operations into separate sessions so you don't have to deal with the 1st level cache issues. Otherwise you will probably want to detach/attach your objects manually as the user above suggests. You could also change the FlushMode on your Session if you don't want things being flushed automatically (FlushMode.MANUAL).
Implement a service layer, take a look at spring's #Transactional annotation, and mark your methods as #Transactional(readOnly=true) where applicable.
Your flush mode is probably set to auto, which means you don't really have control of when a DB commit happens.
You could also set your flush mode to manual, and your services/repos will only try to synchronize the db with your app when you tell them to.