|[ Team LiB ]|
Transaction Isolation Level
Transactions in a distributed environment may have varying degrees of isolation, and as previously mentioned, they can be set programmatically. The degree to which those concurrent transactions can interface with one another is set by the transaction isolation level. The java.sql.Connection interface identifies five levels of isolation defined by integer constants. Not coincidentally, the names of those constants are the same ones used to set the isolation level of EJBs demarcated by the container, except for TRANSACTION NONE, which is not used by EJBs.
The isolation levels are designed to address specific data inconsistency scenarios defined by the ANSI/ISO 92 standard. Let's explore those scenarios in more detail.
A dirty read occurs when a transaction is allowed to read data affected by another transaction before the other transaction commits. For example, assume you have a reservation system that shows all seats available in an amphitheater. Mr. X reserves four seats and pays with his credit card. Mr. Y wants to buy these same four seats, but they show up as being taken. Meanwhile, the credit card verification rejects the transaction and the seats are freed. This situation is acceptable, so dirty reads are allowed in this system.
A nonrepeatable read occurs when a transaction attempts to select the same row twice, but a second transaction has modified or deleted the row in the interim. This situation might lead to unpredictable or incorrect results in the first transaction. In an auction Web site, a buyer sees that the last bid was $5. Another buyer posts a bid for $10 and commits. The first buyer posts a bid for $6, but this bid is rejected right away because there's already a higher bid in the system. During the second transaction, we checked the last bid and got the new value, although the transaction wasn't committed yet. There were two queries, yielding two different results, in the same transaction. This situation could cause trouble in other systems, but is required in the case of a bidding system. This is different from dirty reads because the buyers cannot see any bids that are not finalized (committed).
A phantom read occurs when a transaction reads all rows that meet certain criteria, but a second transaction inserts a new row that meets the same criteria. If the first transaction rereads the rows, the new phantom row appears in the results. In an online bookstore, a client is searching for books by topic. At the same time, an employee is updating the book database with new books. The employee enters the ISBN of a book and its quantity, but doesn't commit (there are other books to enter). The book appears in the search results of the client. This situation is wanted; we want the clients to be able to order the book as soon as possible. Later on, the employee sees that he entered the wrong ISBN, so he erases the book from the database. The client cannot see it anymore. This is different from dirty and nonrepeatable read because the records are added, not modified. The client wouldn't see modified records until his transaction ends.
The TRANSACTION_READ_UNCOMMITTED attribute gives a transaction the capability to read uncommitted data. This is the lowest level of isolation (that is, the least isolated from other transactions). Although this is certainly unacceptable for mission-critical applications, it's a good choice for read-often, update-rarely components. The payoff for data integrity is high performance and low interference. This suffers from the problems of nonrepeatable reads, phantom reads, and dirty reads.
The TRANSACTION_READ_COMMITTED attribute offers the next lowest level of transaction isolation. It denies a transaction to read uncommitted data, but allows a nonrepeatable read as well as phantom reads.
The TRANSACTION_REPEATABLE_READ attribute offers the third level of transaction isolation. It denies a transaction the capability to read uncommitted or updated data, but allows added rows—the phantom read.
The TRANSACTION_SERIALIZABLE attribute offers the highest level of transaction isolation. While the first transaction is running, any modifications from other transactions are prevented from occurring. The transaction runs in a vacuum, insulated from all outside transactions. Although this might be good where data integrity is critical, the high overhead has a negative impact on performance. It's important to note that not all databases support serializable transactions; Oracle is one such example. An example of a situation in which a serializable behavior is required: Imagine a system that stores cars for a car dealer. Then someone wants to buy a car. While that person is looking at the car's description, nobody should be able to change the price (no dirty reads or nonrepeatable reads). Nor should anyone be able to add items to the list of previous owners (no phantom reads). We don't want to see other people modifying, adding, or removing data until the current transaction is finished.
One thing worth noting is the fact that the word serializable has nothing to do with Java's serialization mechanism. It merely means that transactions are performed one at a time.
Table 9.1 summarizes the isolation levels and what problems they do and do not address.
|[ Team LiB ]|