All transactions eventually end, either in a commit or a rollback. If a transaction commits, then all of the 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, then none of the work done through any enlisted resources is made permanent.

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

If multiple resources have been enlisted with the transaction, such as two database connections or a database connection and a JMS connection, then a two-phase commit must be used to end the transaction. As its name implies, the two-phase commit proceeds through two stages. The prepare stage comes first, in which the transaction instructs each resource to prepare itself for a commit. Each resource prepares by evaluating whether a commit will succeed or not, then responding with a vote to commit or rollback. If any resource responds with a rollback during the prepare phase, then all resources are immediately rolled back and the transaction ends with a rollback. If a resource votes to commit, then that resource must ensure that it can commit its work, even if a system failure occurs before the commit occurs.

If all resources vote to commit, then the transaction proceeds to the commit phase. In this phase, the transaction instructs each resource to commit. Resources do not have the option of rolling back at this point. Otherwise, there would be the possibility of some resources committing and others rolling back, which is unacceptable in a single transaction.

Once the actual work of committing or rolling back transactions is complete, the transaction is ended. The transaction is then dissociated from its thread, leaving the thread without a current 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.

It is possible for resources to simulate the 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 still 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, then 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 will work most of the time. In the majority of applications where only a single resource is involved, this technique will work 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 will be 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. However, those applications that need to access multiple resources without risking any inconsistencies should use a JDBC driver that supports two-phase commits and be prepared to handle any performance or maintenance penalties involved.

 
loading table of contents...