Why use sub-transactions?
You might wonder why the scheme of root- and sub-transactions is so complicated in first place. Why not have a single transaction for a session? Why can't we store data in the database immediately whenever a user clicks Save?
The example of Miss Quackfaster and her Boss' car-fax is not only contrived, but also simplistic. We used it to explain the basic mechanism (FIXME). Observe that
- users are spontaneous creatures
- often users don't know what they are doing
- users change their corresponding minds
- units of work can be very complex, especially if data is supposed to be committed together
All this can make single transactions or immediate saving problematic. A less simplistic, more realistic example is that of Miss Quackfaster trying to order an electric pencil sharpener and a lunch for her boss for immediate delivery by the procurement group. Let's say, that, for technical reasons, procurement is supposed to be conducted in bulk, for as many items at once at possible. For her boss' lunch and pencil sharpener, Miss Quackfaster opens the central procurement form and
- opens a separate office supplies window
- remembers that she also must order a microwave burger and French fries for her boss' lunch
- opens another window that displays a menu of burgers and side orders
- picks a burger, commits the order
- opens the side orders menu
- picks French fries from the menu, commits the order
- closes the lunch menu window by committing the lunch orders
- back to the office supplies window, she opens the "pens and pencils" window
- cancels the "pens and pencils" form, because no electric pencil sharpeners are listed
- opens the window for "electrical office supplies"
- finds out that electric pencil sharpeners are out of stock
- she cancels the office supplies form, returns to the central procurement form
- commits the central procurement form that shows the order data for the previously committed burger and French fries (Both will show up in the work-flow of some lunch-worker down the food-chain)
All this takes place during a single transaction started in the Boss window. Note how complicated Miss Quackfaster's way through the maze of decisions and forms is. Also note that
- all the orders belong together logically and are part of the same unit of work.
- one transaction can have multiple sub-transactions
Here is an illustration of Miss Quackfaster's procurement adventure:
As you can see in the illustration, the unit of work is structured as a tree. Just as in the illustration before, green arrows show Commit()
s to the parent transactions, with (13) as the ultimate Commit()
to the database. Note that data can move toward the database only if the parent nodes let them. If Miss Quackfaster decides to cancel a node, the modifications for all its children are discarded. This aids the user in complicated units of work like this: If you cancel a form, all forms you had open before are as good as gone. Building child transactions along the way through the maze of windows aids the programmer, because it is easy to keep track of data. This would be hard (if not impossible) to track in a single client transaction, because then the programmer would have to build his tree-like data structure outside his client transaction. SOME mechanism is required to decide which modifications must be discarded if Miss Quackfaster decides to cancel an entire branch of previous Commit()
-s. Making client-transaction simpler wouldn't make things easier, it would put the burden of managing parents and children on the programmer (you). If your desire a less fancy and more flat, you CAN use a single transaction. The parent/child-architecture of client transactions lends itself very well to the problem branching in units of work, because it can mirror the behavior of users who quite naturally fork, branch and detour to their hearts' content through trees of interconnected domain objects.