Data Concurrency and Consistency (original) (raw)
In the serializable isolation level, a transaction sees only changes committed at the time the transaction—not the query—began and changes made by the transaction itself.
A serializable transaction operates in an environment that makes it appear as if no other users were modifying data in the database. Serializable isolation is suitable for environments:
- With large databases and short transactions that update only a few rows
- Where the chance that two concurrent transactions will modify the same rows is relatively low
- Where relatively long-running transactions are primarily read only
In serializable isolation, the read consistency normally obtained at the statement level extends to the entire transaction. Any row read by the transaction is assured to be the same when reread. Any query is guaranteed to return the same results for the duration of the transaction, so changes made by other transactions are not visible to the query regardless of how long it has been running. Serializable transactions do not experience dirty reads, fuzzy reads, or phantom reads.
Oracle Database permits a serializable transaction to modify a row only if changes to the row made by other transactions were already committed when the serializable transaction began. The database generates an error when a serializable transaction tries to update or delete data changed by a different transaction that committed after the serializable transaction began:
ORA-08177: Cannot serialize access for this transaction
When a serializable transaction fails with the ORA-08177
error, an application can take several actions, including the following:
- Commit the work executed to that point
- Execute additional (but different) statements, perhaps after rolling back to a savepoint established earlier in the transaction
- Roll back the entire transaction
The following table shows how a serializable transaction interacts with other transactions. If the serializable transaction does not try to change a row committed by another transaction after the serializable transaction began, then a serialized access problem is avoided.
Table 12-3 Serializable Transaction
Session 1 | Session 2 | Explanation |
---|---|---|
SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- ---------- Banda 6200 Greene 9500 | No action. | Session 1 queries the salaries for Banda, Greene, and Hintz. No employee named Hintz is found. |
SQL> UPDATE employees SET salary = 7000 WHERE last_name='Banda'; | No action. | Session 1 begins transaction 1 by updating the Banda salary. The default isolation level is READ COMMITTED. |
No action. | SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; | Session 2 begins transaction 2 and sets it to the SERIALIZABLE isolation level. |
No action. | SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------ ---------- Banda 6200 Greene 9500 | Transaction 2 queries the salaries for Banda, Greene, and Hintz. Oracle Database uses read consistency to show the salary for Banda before the uncommitted update made by transaction 1. |
No action. | SQL> UPDATE employees SET salary = 9900 WHERE last_name = 'Greene'; | Transaction 2 updates the Greene salary successfully because only the Banda row is locked. |
SQL> INSERT INTO employees (employee_id, last_name, email, hire_date, job_id) VALUES (210, 'Hintz', 'JHINTZ', SYSDATE,'SH_CLERK'); | No action. | Transaction 1 inserts a row for employee Hintz. |
SQL> COMMIT; | No action. | Transaction 1 commits its work, ending the transaction. |
SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- ---------- Banda 7000 Greene 9500 Hintz | SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- --------- Banda 6200 Greene 9900 | Session 1 queries the salaries for employees Banda, Greene, and Hintz and sees changes committed by transaction 1. Session 1 does not see the uncommitted Greene update made by transaction 2. Transaction 2 queries the salaries for employees Banda, Greene, and Hintz. Oracle Database read consistency ensures that the Hintz insert and Banda update committed by transaction 1 are not visible to transaction 2. Transaction 2 sees its own update to the Greene salary. |
No action. | COMMIT; | Transaction 2 commits its work, ending the transaction. |
SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- ---------- Banda 7000 Greene 9900 Hintz | SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- --------- Banda 7000 Greene 9900 Hintz | Both sessions query the salaries for Banda, Greene, and Hintz. Each session sees all committed changes made by transaction 1 and transaction 2. |
SQL> UPDATE employees SET salary = 7100 WHERE last_name = 'Hintz'; | No action. | Session 1 begins transaction 3 by updating the Hintz salary. The default isolation level for transaction 3 is READ COMMITTED. |
No action. | SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; | Session 2 begins transaction 4 and sets it to the SERIALIZABLE isolation level. |
No action. | SQL> UPDATE employees SET salary = 7200 WHERE last_name = 'Hintz'; -- prompt does not return | Transaction 4 attempts to update the salary for Hintz, but is blocked because transaction 3 locked the Hintz row. Transaction 4 queues behind transaction 3. |
SQL> COMMIT; | No action. | Transaction 3 commits its update of the Hintz salary, ending the transaction. |
No action. | UPDATE employees SET salary = 7200 WHERE last_name = 'Hintz' * ERROR at line 1: ORA-08177: can't serialize access for this transaction | The commit that ends transaction 3 causes the Hintz update in transaction 4 to fail with the ORA-08177 error. The problem error occurs because transaction 3 committed the Hintz update after transaction 4 began. |
No action. | SQL> ROLLBACK; | Session 2 rolls back transaction 4, which ends the transaction. |
No action. | SQL> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; | Session 2 begins transaction 5 and sets it to the SERIALIZABLE isolation level. |
No action. | SQL> SELECT last_name, salary FROM employees WHERE last_name IN ('Banda', 'Greene', 'Hintz'); LAST_NAME SALARY ------------- ---------- Banda 7000 Greene 9900 Hintz 7100 | Transaction 5 queries the salaries for Banda, Greene, and Hintz. The Hintz salary update committed by transaction 3 is visible. |
No action. | SQL> UPDATE employees SET salary = 7200 WHERE last_name='Hintz'; 1 row updated. | Transaction 5 updates the Hintz salary to a different value. Because the Hintz update made by transaction 3 committed before the start of transaction 5, the serialized access problem is avoided. Note: If a different transaction updated and committed the Hintz row after transaction 5 began, then the serialized access problem would occur again. |
No action. | SQL> COMMIT; | Session 2 commits the update without any problems, ending the transaction. |