When you interact with Hibernate, you do so via a Hibernate session. Hibernate sessions are flushed to the database in three situations:
- When you commit a (Hibernate) transaction.
- Before you run a query.
- When you call session.flush().
However, it is extremely important to understand the second of these situations – session flushing prior to running a query. This does not happen before every query! Remember, the purpose of the Hibernate session is to minimise the number of writes to the database, so it will avoid flushing to the database if it thinks that it isn’t needed. Hibernate will try to work out if the objects currently in your session are relevant to the query that is running, and it will only flush them if it thinks they are. You can easily see the effects of this behaviour. For example, suppose I have Customer and Order objects. A customer has a set of orders. To begin with, I’ll just create the orders without any reference to the customers:
Order order1 = new Order(); order1.setOrderTotal(29.99); Order order2 = new Order(); order2.setOrderTotal(8.99); Order order3 = new Order(); order3.setOrderTotal(15.99); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); session.save(order1); session.save(order2); session.save(order3);
At this stage, the three objects will be saved to the database. Now let’s create a customer and save them:
Customer customer = new Customer(); customer.setForename("Hedley"); customer.setSurname("Proctor"); session.save(customer);
Okay, now the customer is in the database. Let’s now create the link between the customer and their orders:
order1.setCustomer(customer); order2.setCustomer(customer); order3.setCustomer(customer);
Now the Hibernate session is dirty, meaning that the objects in the session have changes that haven’t been persisted to the database yet. If we run an SQL query, Hibernate doesn’t know to flush the session, and the results you get back do not reflect the current states of the objects:
Query query = session.createSQLQuery("select id,customer_id from orders"); List results = query.list();
Here are the results of this query:
Hibernate: select id,customer_id from orders
Even running a Hibernate query in HQL or with a criteria won’t cause the session to flush if Hibernate doesn’t think the query concerns the objects that are dirty. e.g.
Query query = session.createQuery("from Customer");
This won’t cause a session flush because it is the Order objects that are dirty. Hence, a Hibernate query involving these objects will cause a session flush. e.g.
Query query = session.createQuery("from Order");
If you want to see this code running, it is available from github:
This article is part of a series on Hibernate. You might be interested in some of the others:
Hibernate query limitations and correlated sub-queries
Bespoke join conditions with Hibernate JoinFormula
Inheritance and polymorphism