Welcome!

Peter Holditch

Subscribe to Peter Holditch: eMailAlertsEmail Alerts
Get Peter Holditch via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Article

Transactions, where do they begin and end?

Transactions, where do they begin and end?

As we've discussed over the past few issues, JTA-style transactions provide a way for multiple data updates to be tied together so application logic can operate safely in the assumption that it will succeed or fail consistently, even in the face of technical failures along the road.

There are, however, times when you do not want all the work you do to succeed or fail in one big lump.

Among the scenarios that may lead you to want to break work up into smaller chunks are:

  • Progress/error logging
  • Long-running operations
  • Wide-spanning operations
I discussed the last two scenarios in a previous article (WLDJ, vol. 1, issue 2) ­ transactions hold locks on data. Holding locks for a long time may cause your application to freeze, unable to access data it needs. The wider the span of a transaction (measured in terms of data elements touched and hence locked), the more likely you are to run into deadlock situations, and the longer running the transactions will be ­ running right back into the previous bullet.

The first point, about logging, is more of a business logic­driven consideration. Many people use databases to record events in their systems. Take the example of an audit log. Imagine a banking application that logs all fund movements. Imagine also a teller trying to fraudulently withdraw $10,000 from some account. In order to track the fraud, the application users are likely to want to look through the audit log. If the fraudster had tried 1,000 withdrawals, then the auditors would want to see 1,000 pieces of evidence. They would be pretty ticked off if they only saw 900 records, since 100 withdrawals failed, and the writing of the log records rolled back with the failed withdrawals. Clearly, the log record cannot be written in the same transaction as the withdrawal.

Transactions: Where Do They Live?
When you write the code to start an XA transaction, it's associated with the thread of execution, and irrespective of what methods in whatever classes you call, any database connections that you get and use will inherit the transaction context from the thread. Thus, when the transaction is finally committed, all the work that you've caused to be done ­ whether or not it was in utility classes that you don't even know the contents of ­ will complete as a transactional atomic unit. Given that the transaction lives in the thread and is so pervasive, how do you break up the work done by your thread of control into multiple transactions?

Transactions, What A State!
The answer to this problem is that transactions can be in more states than simply active or inactive. They can also be suspended. A suspended transaction is still not complete ­ the timer controlling the timeouts etc. is still running, and can roll back of its own accord if the timeout is exceeded ­ but it's no longer associated with the current thread of execution.

Now, you're at liberty to start a new one, if you like (in our example above it's this transaction that would be responsible for the audit-log writing) This new transaction is quite independent of the old one ­ it can commit or abort as required by its own business semantics ­ and after whatever logic it represents has completed, the old transaction can be resumed and carry on where it left off (provided it didn't time out behind your back, as previously noted).

Anyone For Tennis?
In fact, for the real rocket scientist, a transaction can be suspended in one thread and resumed in a different one, which means that your code can play "transaction tennis," passing transaction objects back and forth as it pleases. This is, however, a very bad idea. For maximum reuse, code should leave the transactional state as it found it. If you're writing a class that is making all kinds of assumptions about the state of the current transaction, then the chances of it being useful in another future situation are pretty limited. It's a basic rule of encapsulation that you shouldn't expose your inner workings through your interfaces, and transactions fall firmly into the category of inner workings. By all means, write code that suspends the current transaction (if any) before performing operations that need to be self-contained, so long as the transaction is resumed again afterwards. Because transactions are omnipresent in a thread, you need to make sure you don't code any nasty surprises for yourself. As we all know, there is no more difficult bug to track than one that involves the operating environment changing unexpectedly. That, after all, is why the Java language excommunicated the concept of the pointer.

More Stories By Peter Holditch

Peter Holditch is a senior presales engineer in the UK for Azul Systems. Prior to joining Azul he spent nine years at BEA systems, going from being one of their first Professional Services consultants in Europe and finishing up as a principal presales engineer. He has an R&D background (originally having worked on BEA's Tuxedo product) and his technical interests are in high-throughput transaction systems. "Of the pitch" Peter likes to brew beer, build furniture, and undertake other ludicrously ambitious projects - but (generally) not all at the same time!

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.