All transactions eventually end, either in a commit or a rollback. If a transaction commits, all work done through the resources enlisted over the course of that transaction is made permanent and visible to other transactions. If a transaction rolls back, none of the work done through any enlisted resources is made permanent.

If a single resource has been enlisted with the transaction, the commit or rollback result is passed directly to the resource. This is the most common case, because most applications make use of a single database and communicate with no other transactional resources.

If multiple resources were enlisted with the transaction, such as two database connections or a database connection and a JMS connection, a two-phase commit must be used to end the transaction. A two-phase commit is comprised of two stages, prepare and commit:

After a transaction commits or rolls back, it ends and is dissociated from its thread, leaving the thread without a transaction.

Simulating Two-Phase Commit

A two-phase commit is much more complex than a commit involving a single resource. Not only is it more complex for the application server, but the resources themselves must be fairly advanced to be able to ensure that they can commit their work even if the system fails. As it turns out, few databases support this ability, and even fewer JDBC drivers include this support (sometimes called XA support). As a result, very few applications make use of multiple resources at once.

Resources can simulate two-phase behavior, even if they do not inherently support two-phase commits. This allows JDBC drivers that do not support the two-phase commit protocol to work with the application server’s two-phase commit mechanism. A resource can simulate the two-phase protocol by committing in the prepare phase, and ignoring the commit phase. If the commit succeeds, the resource votes to commit, otherwise the resource votes to rollback. The transaction can proceed as normal, using both resources that understand the two-phase commit protocol, and those that simulate it.

This works most of the time. In the majority of applications where only a single resource is involved, this technique works flawlessly. However, if a transaction involves multiple resources then there are instances where a resource might commit while the others roll back. If, during the prepare phase, the resource commits but then a subsequent resource votes to rollback, it is too late for the first resource to rollback, so there is an inconsistency.

Fortunately, these situations arise very rarely. Because of this, and because two-phase commits can cause performance problems, resources and drivers that support true two-phase commits are still fairly uncommon. In fact, Dynamo’s default configuration uses a JDBC driver configured to simulate two-phase commits. This driver should be sufficiently robust to handle the majority of applications.

loading table of contents...