Earlier, we defined a transaction as a set of related operations, whose completion is an all-or-none affair. In a simple case, a transaction begins, issues requests, commits the changes and completes. This is called a flat transaction. If an error occurs, the transaction is aborted, and all evidence of its existence is erased from the permanent stores, including databases and other resources, such as persistent message queues. Either all of the changes are made, or none at all.
Let's look at an example of a transaction from the VideoMagix application, introduced in Chapter 2. In his book, Analysis Patterns: Reusable Object Models (Addison-Wesley, ISBN 0-201-89542-0), Martin Fowler examines the Inventory and Accounting Patterns, and discusses the essential abstraction of an account. There is a striking similarity between a book-keeping account and the customer records in the VideoMagix application. Fowler says that an accounting system must not only report on the current state of an account, but also on all of the transactions which have affected that state. He creates a class,
. An Entry
is a record of a change to the account. In UML, this relationship might look like this:Entry
In this diagram we see that a
and a CustomerAccount
enter into an association which is documented by two VideoTape
objects:
Entry
CustomerAccount
to show that a tape was rentedVideoTape
account to show that a particular customer rented the tapeA transaction links two or more entries into a single entity, so that for one to happen, the other must be successful. This approximates the key idea in double entry accounting, in which each credit must be offset by a balancing debit. It enforces the idea that value is never created or destroyed, it is just reallocated from one account to another.
This diagram attempts to capture the transactional relationship. Each transaction has two entries, and each entry is a member of a single transaction. Note that I've added a constraint:
. The two entries must offset one another. You mark a constraint by placing it in curly braces {Entry1 + Entry2 = 0}
.{}
A constraint is an adornment which restricts the relationship
This diagram illustrates the essence of double-entry accounting. Each time the customer account is updated to indicate that the customer has rented a video tape, an offsetting, or balancing entry is made in the video tape account indicating that the tape has been rented.
If, in the middle of this transaction you found that you could not update the videotape, you would then roll back the update to the customer account. Again, either both entries succeed or neither can.
Once a transaction is "committed", it cannot be undone. Of course, in some circumstances, another transaction (called a compensating transaction) may be used to negate the effects of this transaction. An example would be a transaction that recorded a sale and updated an inventory table. A second transaction could be used to change or remove the record of the sale and reset the inventory figures.
A compensating transaction is not the same as a balancing or offsetting entry, though this can cause some confusion. A compensating transaction is a second, discrete transaction (also with two entries in this case) which undoes the effect of the first transaction.
Notice also that running a compensating transaction is not the same thing as aborting a transaction. Let's imagine that this database has a table,
, which keeps track of the number of times the price of each item has changed. In this case, running a transaction and a compensating transaction would change the priceVolatility
table, adding two entries and making the price look more volatile. An aborted transaction would not create any additions to the priceVolatility
table. The significant difference is that an aborted transaction removes all record of the transaction, while a compensating transaction undoes the net effect but the records for both the original and compensating transaction exist.priceVolatility