Compound Theory

v2.0

Categories

  1. Transfer
  2. ColdFusion
  3. JRuby
  4. Java
  5. ColdSpring
  6. Squabble
  7. JavaLoader
  8. ColdDoc
  9. 2ddu
  10. AsyncHTTP
  11. OO Analysis and Design
  12. Flex
  13. Railo
  14. XML / XSL
  15. Hibernate
  16. ColdFusion Builder
  17. Fall
  18. Ubuntu
  19. XHTML / CSS
  20. Eclipse
  21. Git
  22. Oracle Database
  23. Usability / UI Design
  24. webDU
  25. cf.Objective()
  26. LWJGL
  27. cf.Objective(ANZ)
  28. Captcha
  29. MAX
  30. Melbourne CFUG
  31. Martial Arts
  32. Random Things
  33. Conduit

Recent Posts

Projects

Recent Comments

28 January 2010 08:32 AM 15 Comments

ColdFusion 9 ORM and Transactions - It Does Not Mean What You Think it Means.

In one of my favourite lines from the Princess Bride -

[Vizzini has just cut the rope The Dread Pirate Roberts is climbing up]
Vizzini: HE DIDN'T FALL? INCONCEIVABLE.
Inigo Montoya: You keep using that word. I do not think it means what you think it means.


..and when using Transaction support with ColdFusion 9 ORM and Hibernate Sessions...It did not do what I thought it did. It did something else.

To give some back story: As we have discussed previously, a Hibernate Session is meant to flush at the end of a Hibernate marked Transaction.

So if we are talking to Hibernate natively (for example set up with JavaLoader), and had the following code:
mySession = sessionFactory.openSession();

foo = mySession.get("Foo", 1);
foo.setBar("fooBar");

trans = mySession.beginTransaction();

mySession.save(foo);

trans.commit();

mySession.close();
Which then translates to the following:
  1. Start a Hibernate Session
  2. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  3. set the property 'Bar' on foo
  4. Start a Hibernate Transaction, which is tied to the Hibernate Session
  5. Tell the Hibernate Session to save() our Entity foo
  6. Commit our Hibernate Transaction, which will flush the Hibernate Session
  7. Close the Hibernate Session

If we attempt to do the same thing in ColdFusion, it may look something like this:

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

transation {
    EntitySave(foo);
}

Which you would think would work exactly the same as above. Except or one small thing - It Doesn't.

If you read the ColdFusion Documentation on ORM Transactions, it states:

When <cftransaction> begins, any existing ORM session is flushed and closed, and a new ORM session is created. The <cftransaction> can be committed or rolled back using appropriate ColdFusion tags in <cftransaction>. When the transaction ends and has not been committed or rolled back explicitly, it is automatically committed and the ORM session is closed. If there is any error inside the transaction, without any exception handling, the transaction is rolled back.


This means that the above ColdFusion code, will actually perform like so:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  3. set the property 'Bar' on foo
  4. Hit the start of the Transaction, flush the current Hibernate Session, close it, and then start another one.  At this point, foo has been persisted to the database, and is now detached (and remember detached is generally bad)
  5. Call EntitySave() on the now detached object foo
  6. Commit the Hibernate Transaction, and flush the Hibernate Session
  7. Flush the Hibernate Session, when the ColdFusion Request Ends

Or if you want to look at it another way, it would be the equivalent of doing the following native communication with Hibernate:
mySession = sessionFactory.openSession();

foo = mySession.get("Foo", 1);
foo.setBar("fooBar");

//foo actually gets persisted to the DB at this point
mySession.flush();
mySession.close();
mySession = sessionFactory.openSession();

trans = mySession.beginTransaction();

//foo is now detached
mySession.save(foo);

trans.commit();

mySession.flush();
mySession.close();

The big question at this point, is of course - Well, why does ColdFusion do it this way then?

There is actually a very good reason, although that reason (imho) is based on a few assumptions. 

The first assumption, is that you are going to write your ORM interactions inside your transaction block, like so:

transation {
    foo = EntityLoad("Foo", 1, true);
    foo.setBar("fooBar");

    EntitySave(foo);
}

The second  assumption is that, as a developer you will leave the ORM setting flushatrequestend set to its default of true, and therefore a split between the Hibernate Sessions is required.

For example, if we had the following code:

transation {
    foo = EntityLoad("Foo", 1, true);
    foo.setBar("fooBar");

    myMethodHereThrowsAnException();

    EntitySave(foo);
}

If we didn't have separate Hibernate Sessions, or at least clearing of the Session after Hibernate Transaction rollback, , the following would occur:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Start the Hibernate Transaction
  3. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  4. set the property 'Bar' on foo
  5. Throw an exception, which causes the Transaction to rollback
  6. The request ends, the Hibernate Session is flushed, and foo gets saved back to the database, since it is still available in the Hibernate Session.
Which is very much against the nature of a rolled-back transaction.

Instead, what actually happens is:
  1. Start a Hibernate Session with the ColdFusion Request
  2. Start the Hibernate Transaction, which closed the above Session, and starts a new one
  3. Retrieve Entity 'Foo', with a key of 1, and assign it to a variable foo
  4. set the property 'Bar' on foo
  5. Throw an exception, which causes the Transaction to rollback
  6. The Transaction end closes the current Hibernate Session, and creates a new one
  7. The request ends, the Hibernate Session is flushed, and nothing gets saved to the database, as there is nothing in the current Hibernate Session
Given the above assumptions, this is much better, since we want to have the Transaction actually rollback.

That all being said, what happens to those of us that want to work, or have an architecture that inclined towards our previous example:

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

transation {
    EntitySave(foo);
}

I.e. We want to have our Transaction interact with the current Hibernate Transaction, and not flush at the end of the ColdFusion request, which, I find to be the solution I prefer for when building applications with Hibernate.

What can we do then?

There are two things that need to be done, if we want to do this kinda of approach. The first is, to set the ORM setting flushatrequestend to false.  This means that the Hibernate session won't flush at the end of the ColdFusion request, and we have complete control over when it does flush.

To make sure the Transaction interacts with the current request, we can't use <cftransaction> or a transaction {} block, we have to natively interact with the Hibernate Session directly, which is quite straight forward.

foo = EntityLoad("Foo", 1, true);
foo.setBar("fooBar");

trans = getORMSession().beginTransaction();

try
{
    EntitySave(foo);

    trans.commit();
}
catch(Any exc)
{
    trans.rollback();
    rethrow;
}

We have to do the extra work to manage the commit and/or rollback of the Transaction manually, but this something that could be implemented with a UDF or using Aspect Oriented Programming for reuse.

Now I can use Transactions to demarcate when I want the Hibernate Session to be flushed, and I'm not tied to wrapping my entire Entity operations inside a <cftransaction> block.

This is something I really like about how Adobe implemented the ORM integration.  If I don't particularly like the way an individual aspect has been implemented, I have direct access to the underlying engine, and can therefore interact with it in whatever way that suits the way I develop and thearchitecture of my application.

Now Transactions mean what I think they mean.
 
UPDATE 28/10/01:
I just wanted to add a small conclusion to this post, that sums what I am trying to get across simply.
 
Basically what this all boils down to is: If you are using <cftransaction> or a transaction{} block, make sure you are wrapping them around the entire operation, not just the EntitySave() portion at the end, as otherwise bad things can happen.

If you want to just wrap transactions around the EntitySave() part of your code, you will need to use native Hibernate Transactions like I have done above.
 
Hopefully that boils the large post above into a nice tasty nugget of knowledge that is far easier to swallow.

Presenting and Teaching at cf.Objective() 2010

I'm a little behind the times on this blog post - but I am presenting and also teaching a course at cf.Objective() this year.

I will be presenting 2 sessions at the conference:

Dependency Injection Redefined - ColdSpring 2.0: Narwhal

ColdSpring 2.0, codenamed 'Narwhal', is a project that has been going on a little 'behind the scenes', except for the occasional tweet from either myself, or Chris Scott.

In this presentation, we'll look at some of the motivations behind the complete rewrite of ColdSpring for the 2.0 version, and some of the new features that will be available that should make dependency injection easier, and way more flexible than ever before.

I've had in my to-do list a reminder to write a long blog post on what is going on with Narwhal, which I should write at some point soon, so you have a good idea what to look out for.  That being said, Narwhal is taking shape nicely, and I think is going to be a very powerful addition to the ColdFusion framework landscape.

Advanced Java & ColdFusion Integration with JavaLoader 1.0

This talk will focus on the new features of JavaLoader 1.0, and how you can use them to integrate Java with your ColdFusion platform in some new and exciting ways.  If you are interested in JavaLoader 1.0, check out this previous blog post, it gives you a good run down on the new features it brings to the table.

We will also be investigating some of more common 'gotchas' with Java and ColdFusion integration, especially around ClassLoader issues, which should be useful for all involved.


Bob Silverberg and I are also going to be a teaching a 2 day training course, just before cf.Objective():

Hands-On ColdFusion ORM Training

This will be as very hands on session, where Bob and I will be going through building an application using ColdFuson 9's Object Relational Mapper from beginning to end.  This will include many best practices, discussions as well as theory about how the underlying Hibernate engine works with ColdFusion.  No ORM/Hibernate experience necessary.

More detail on the course can be found on our website, and also on the preconference page, where you can also check out all the other fantastic training content.

Don't forget that the early bird pricing for both conference tickets, and training finishes on the 29th of January, which is coming up soon!

cf.Objective() is looking to be a great conference. Hope to see you there!
20 January 2010 11:48 AM 1 Comment

JavaLoader 1.0 Beta 2 Released

This release of JavaLoader 1.0 includes the following fixes and enhancements:
If you aren't aware of the new functionality in JavaLoader 1.0, you can have a look at my previous blog post , the documentation and/or the presentation I did at MAX for more information.

Credit and thanks to Fred Roeber for his contributions to the NetworkClassLoader in JavaLoader.

If you are interested in hearing more about ColdFusion and Java integration please come to cf.Objective(), where I will be presenting on Advanced Java & ColdFusion with JavaLoader 1.0.

In the mean time, download JavaLoader, and please report any bugs that you find.