Figure 3.17 The transaction boundaries in the default case. If a purchase exceeds a customer's credit
limit, customer creation will be rolled back, but the purchased food will still be removed from the inventory.
high enough credit limit for a purchase, the creation of their account will be reversed.
(More accurately, the account creation is never committed, which looks the same
from the outside.)
But the shop purchase uses methods from both AccountingImpl and InventoryImpl .
Any failure in either method should cause the whole purchase to be rolled back and all
database changes undone. You could do this by catching exceptions in the purchase()
method and then writing new database operations to undo everything, but you risk get-
ting into a world of trouble quickly. What if the attempt to reverse the problematic trans-
action fails? What if a Throwable is thrown and you don't remember to catch it?
By far the neater—and simpler—solution is to wrap the whole purchase in a single
transaction (figure 3.18). That transaction is propagated to the removeStock and
chargeToAccount methods. These methods need a transaction to be present when the
method is entered, but there's nothing in their Blueprint metadata that says it has to be
a new transaction. Any exception in either method causes everything to be rolled back.
How do you create this broad-scope transaction? Blueprint, again! All that's
needed is to add the following line to the bean definition for ShopImpl :
<tx:transaction method="*" value="Required" />
This ensures that every method on the ShopImpl class gets a transaction. This transac-
tion is propagated to other classes called by ShopImpl so that if one call within a
method fails, the entire method is rolled back. What's so cool about this is how tiny
the change is. It takes more characters to explain than it does to implement!
The coolness isn't over yet, though, because OSG i gives you something even
cooler. The persistence bundle can be rebuilt and dropped into the load directory
again without bouncing the OSG i framework. The runtime detects the new code in
Figure 3.18 Better transaction boundaries. If a purchase exceeds a customer's credit limit, no food will
be removed from the inventory.