Feel free to skip this page if you already understand transactions and just want to see how to define transactions in Spring using annotations.
The core idea behind a transaction is that it's a complex operation completed as an all-or-nothing set of simpler operations. If one of the simpler operations fails, then none of the operations should be applied.
The classic example is making a purchase, and indeed this is probably where the name "transaction" comes from. There are several steps:
A failure could happen at any of those steps. For example, at step 1, if the buyer doesn't have enough money, then the transaction should fail. (We wouldn't add funds to the seller's account and we wouldn't decrease product inventory.) At step 2, if the seller's account has been frozen due to suspected involvement in illegal activities, then the transaction should fail. At step 3, if the product is out of stock, then again the transaction should fail.
That's just the classic example. There are other examples that are transactions in the technical sense even though a non-technical person wouldn't normally regard them as transactions per se. For instance, my web site allows end users to submit comments on articles. I have a database table for comments and a separate link table that links comments to their associated articles. (I have it this way because I want to be able to relate comments to other entities as well.) So to add a comment, I need to insert a record into the comment table and then another record into the link table. If either of those inserts fails, then I don't want to run either one. That's a transaction too, at least in the narrower technical sense that we're discussing here.
I would say that the all-or-nothing nature of transactions is their defining characteristic, but it is generally recognized that there are four major characteristics we have in mind when we call something a transaction. They are the ACID properties.
ACID is an acronym that stands for atomic, consistent, isolated and durable. An operation is a transaction if and only if it has these four characteristics, which I'll describe briefly:
sell(you, 5, widget) transaction.
The consistency property means that after a transaction completes, the
database (or whatever transactional resource we're using) matches up
with the real world.Now that we know what transactions are, we need to understand how individual transactions are actually specified. Defining a transaction involves picking a chunk of code (maybe a method, maybe a set of methods, maybe a block of code inside a method) and setting values for the following five parameters:
synchronized keyword: if one synchronized method calls
another on the same class, then the protected scope includes both
methods, not just one, and so the boundaries do not coincide with a
single method. But the difference is that with transactions you have
a lot more flexibility as far as defining the boundaries. Certainly
it is possible to enter a transaction starting from one method and
then include additional method calls within the scope of that initial
transaction. But you can do other things too, such as declare that
calls to other methods open up new transactions, or that a given
method must always run within the scope of an existing transaction,
etc. I won't go over all the options here but there are seven and you
can see them here: transaction
propagation options. Probably PROPAGATION_REQUIRED
is the most typical.ISOLATION_READ_COMMITTED and
ISOLATION_REPEATABLE_READ. The
ISOLATION_READ_UNCOMMITTED is so weak as to be almost
useless in practice, and ISOLATION_SERIALIZABLE is so
strong that you don't want to use it unless you really, really need
the safety it provides: it's a concurrency-killer.With that overview concluded, let's now examine Spring's annotation-based transaction management. It is ridiculously straightforward.