ColdFusion 9 ORM – More on Flushing Hibernate Sessions

Hopefully with my previous article, I've got you understanding how Hibernate Sessions
work behind the scenes of ColdFusion.  However, there is one statement
I made that requires further clarification before we go any further.

I wrote:
"This means that changes to your objects will also not be persisted to your database, until the end of your ColdFusion request, as that is when the Hibernate Session is closed."

Technically this isn't exactly true, but it was a concept that confused me a lot
when first starting with Hibernate, so I wanted to get people thinking
in the right direction without complicating things too much.

The Problem

For example, a situation like this made me scratch my head for a long time when I first started working with Hibernate:

We have 5 Musicians in our database, and we want to delete one, and then re-list all of them again.


<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>
<cfset EntityDelete(musician)>

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">


And we would see a result like:

Tom, Jerry, Ben, Bob, Richard

We are now deleting!

Tom, Jerry, Ben, Bob, Richard

This shows me exactly the same data we before and after my EntityDelete().  Wait… what? Didn't I delete Musician Number 3?

The fact of the matter is, yes, we deleted Musician #3, except since the Hibernate Session hasn't been flushed yet, the data hasn't been persisted to the database.  Therefore, when we run out HQL query, we see all the Musicians!

Hibernate Session Flushing

Before we go directly into how to solve this problem, what does the Hibernate documentation say about when Session Flushing actually occurs?

This process, called flush, occurs by default at the following
points:

  1. before some query executions

  2. from org.hibernate.Transaction.commit()

  3. from Session.flush() 

So what does that actually mean in terms of ColdFusion?

  1. Before some query executions – So at some arbitrary points during the Hibernate Session life cycle it may flush.  Obviously not something we can rely upon.
  2. At the end of a Transaction. So if we our code in a <cftransaction> block, it should flush at the end of that transaction, and therefore the changes to our objects will be persisted in the database.
  3. When we call ORMFlush(), or at the end of a Session when it is called implicitly.

Therefore, if we wrap the relevant code in or Transaction, like so:


<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<cftransaction>
<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>
<cfset EntityDelete(musician)>

</cftransaction>
<!--- Session should be flushed now --->

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

We should get a result of:

Tom, Jerry, Ben, Bob, Richard

We are now deleting!

Tom, Jerry, Bob, Richard

Alternatively, we could also do:

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

<p>We are now deleting!</p>
<cfset musician = entityLoad("Musician", 3, true)>

<cfset ORMFlush()>
<!--- Session should be flushed now --->

<cfdump var="#ormExecuteQuery('from Musician')#" label="query">

And we would also see the same results.

So as you can see it is not exactly
true that your object data will only get persisted at the end of you
request, as you actually have a lot of control over exactly when the Session gets flushed.

It is important to note that 9/10 times you probably won't care when the Session gets flushed
and the changes to your objects actually get persisted in the
database.  However, there will be instances in which you will care, and
your code depends upon having your data persisted in your database.  You
now have the tools to manage your persistence life cycle and know what
is going to happen when.

Leave a Comment

Comments

  • Ben Nadel | July 21, 2009

    Mark, is there a good introductory book to Hibernate that you would recommend to someone who has never worked with object-based persistence?

  • Thomas MEssier | July 22, 2009

    Hey Mark,

    Had a quick question regarding the examples above. When you do an EntityLoad() followed by EntityDelete() for the loaded entity, will Hibernate know that since you just loaded the object to do a delete that it doesn’t need to run a select statement and can only use a delete statement? Or will it run the select statement anyway?

  • Mark | July 22, 2009

    @Ben,
    I started with a book called ‘Harnessing Hibernate’, by O’Reily. I found it was a great book for me, as it covered just enough to get me started, ad gave you enough to point you in the right direction without giving you every single minute detail, which matches up very well with how I like to learn (I half read, half explore documentation at the same time). It also covers aspects like Eclipse integration, Spring, Maven, Ant etc. which were really useful to know long term.

    That being said, if you are looking for something a little more comprehensive, I’ve heard good things about ‘Java Persistence with Hibernate’. I’ve not read it personally, but the same publisher put out ‘Spring in Action’, which was a fantastic book on Spring.

  • Mark | July 22, 2009

    @Thomas,
    I would expect Hibernate to run the SQL to get the object.

    Hibernate really has no way to know what your code flow is going to be between the EntityLoad(), and EntityDelete() function calls, so it will probably need to load that data in case you do something with it in between.

    That being said, easiest way to find out – give it a shot! Turn on SQL Logging, and see what happens :D

  • Leigh | July 22, 2009

    @Mark,

    Assuming there actually was a legitimate need to call ORMFlush() in a request, a) are there any downsides of calling it too frequently and b) is there any magic range (good or bad)? I would guess calling it too frequently might reduce some of the performance enhancements gained by using Hibernate?

    -Leigh

  • Mark | July 22, 2009

    @Leigh,
    I can’t see there being a ‘magic number’ per se. If you need to flush the cache you don’t often have a choice at that point.

    If you don’t need to – don’t do it. Let Hibernate / CF handle it itself.

    It’s one of those ‘how long is a piece of string’ arguments, as it depends on what your application is doing.

  • Leigh | July 22, 2009

    @Mark,

    Yes, I hear you. But since my Hibernate book has not arrived yet, I was just curious if any bad things happened if ORMFlush() was severely overused (other than the obvious). But as with most things, it sounds like it is one of those "it depends" situations.

    -Leigh

  • Thomas Messier | July 22, 2009

    @Mark,
    I wanted to do that but right now the ORM sql calls don’t show up in the SQL debug output. I guess I’ll have to go back to pure java and see if I can get it to output that way somehow.

  • Leigh | July 22, 2009

    @Thomas,

    I was trying to figure that out myself. They do get appended to the server log files. I do not know if they are accessible from the debug output ..

  • Mark | July 22, 2009

    @Thomas,
    If you turn on logging:
    http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSED380324-6CBE-47cb-9E5E-26B66ACA9E81.html#WSFF090FD3-98D9-4954-B26D-F4709E00F452

    It shows up in the console output and/or the server logs.

    It’s a bit of a pain that only console / file based logging is allowed, hopefully they fix it to show up in the CF debug output before final release.

    I tend to run CF from the console regardless, as it useful for debugging, but it would be nice if you didn’t have to do that.

  • Ben Nadel | July 28, 2009

    Thanks Mark, I’ll check out those books!

  • Dutch Rapley | October 22, 2009

    Mark,

    Great posts on Hibernate. I just wanted to add an additional explanation to why a flush occurs at the end of a transaction.

    Technically, when using transactions, a flush occurs twice. Once, before a transaction starts, and again at the end.

    When a transaction starts, any existing/open hibernate sessions are immediately flushed and closed. A new hibernate session is opened at the beginning of the transaction. When the transaction completes, the session that was opened when the transaction started is flushed and closed.

    Hope this clarifies to anyone who was wondering why hibernate sessions were flushed after a transaction.

  • Mark | October 22, 2009

    @Dutch – that is totally true. Although, only the case for ColdFusion when using <cftransaction> (not true for general Hibernate usage). Generally speaking, I don’t think this is a great thing, and I plan on writing a post on how to avoid the way it has been implemented.

  • Dutch Rapley | October 22, 2009

    yeah, thanks for the heads up in the non-CF Hibernate. I’ve got Hibernate In Action on deck on hoping to get to it by this weekend. Hoping it’ll be a good foundation for hibernate in general as well as for hibernate in CF.

  • David Sanderson | November 24, 2009

    Has anyone had any problems in using <cftransaction> in large scale applications? Adobe makes it seem like it’s tricky business.
    "A <cftransaction> could prevent scalability in highly concurrent applications because it locks a database for a transaction that could run for a longer time."
    http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WS2F0C1CDB-4CAF-42fd-B7D9-500D82C0136A.html

    Then it goes on to talk about using Optimistic concurrency control. Has anyone used that?