Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Semestr2 / 1 - Oracle / PL_SQL / b14261.pdf
Скачиваний:
27
Добавлен:
12.05.2015
Размер:
4.36 Mб
Скачать

Overview of Transaction Processing in PL/SQL

END;

/

The SET TRANSACTION statement must be the first SQL statement in a read-only transaction and can only appear once in a transaction. If you set a transaction to READ ONLY, subsequent queries see only changes committed before the transaction began. The use of READ ONLY does not affect other users or transactions.

Restrictions on SET TRANSACTION

Only the SELECT INTO, OPEN, FETCH, CLOSE, LOCK TABLE, COMMIT, and ROLLBACK statements are allowed in a read-only transaction. Queries cannot be FOR UPDATE.

Overriding Default Locking

By default, Oracle locks data structures for you automatically, which is a major strength of the Oracle database: different applications can read and write to the same data without harming each other's data or coordinating with each other.

You can request data locks on specific rows or entire tables if you need to override default locking. Explicit locking lets you deny access to data for the duration of a transaction.:

With the LOCK TABLE statement, you can explicitly lock entire tables.

With the SELECT FOR UPDATE statement, you can explicitly lock specific rows of a table to make sure they do not change after you have read them. That way, you can check which or how many rows will be affected by an UPDATE or DELETE statement before issuing the statement, and no other application can change the rows in the meantime.

Using FOR UPDATE

When you declare a cursor that will be referenced in the CURRENT OF clause of an UPDATE or DELETE statement, you must use the FOR UPDATE clause to acquire exclusive row locks. An example follows:

DECLARE

CURSOR c1 IS SELECT employee_id, salary FROM employees

WHERE job_id = 'SA_REP' AND commission_pct > .10

FOR UPDATE NOWAIT;

The SELECT ... FOR UPDATE statement identifies the rows that will be updated or deleted, then locks each row in the result set. This is useful when you want to base an update on the existing values in a row. In that case, you must make sure the row is not changed by another user before the update.

The optional keyword NOWAIT tells Oracle not to wait if requested rows have been locked by another user. Control is immediately returned to your program so that it can do other work before trying again to acquire the lock. If you omit the keyword NOWAIT, Oracle waits until the rows are available.

All rows are locked when you open the cursor, not as they are fetched. The rows are unlocked when you commit or roll back the transaction. Since the rows are no longer locked, you cannot fetch from a FOR UPDATE cursor after a commit. For a workaround, see "Fetching Across Commits" on page 6-35.

When querying multiple tables, you can use the FOR UPDATE clause to confine row locking to particular tables. Rows in a table are locked only if the FOR UPDATE OF

6-34 Oracle Database PL/SQL User’s Guide and Reference

Overview of Transaction Processing in PL/SQL

clause refers to a column in that table. For example, the following query locks rows in the employees table but not in the departments table:

DECLARE

CURSOR c1 IS SELECT last_name, department_name FROM employees, departments WHERE employees.department_id = departments.department_id

AND job_id = 'SA_MAN' FOR UPDATE OF salary;

As shown in Example 6–41, you use the CURRENT OF clause in an UPDATE or DELETE statement to refer to the latest row fetched from a cursor.

Example 6–41 Using CURRENT OF to Update the Latest Row Fetched From a Cursor

DECLARE

my_emp_id NUMBER(6); my_job_id VARCHAR2(10); my_sal NUMBER(8,2);

CURSOR c1 IS SELECT employee_id, job_id, salary FROM employees FOR UPDATE; BEGIN

OPEN c1; LOOP

FETCH c1 INTO my_emp_id, my_job_id, my_sal; IF my_job_id = 'SA_REP' THEN

UPDATE employees SET salary = salary * 1.02 WHERE CURRENT OF c1; END IF;

EXIT WHEN c1%NOTFOUND; END LOOP;

END;

/

Using LOCK TABLE

You use the LOCK TABLE statement to lock entire database tables in a specified lock mode so that you can share or deny access to them. Row share locks allow concurrent access to a table; they prevent other users from locking the entire table for exclusive use. Table locks are released when your transaction issues a commit or rollback.

LOCK TABLE employees IN ROW SHARE MODE NOWAIT;

The lock mode determines what other locks can be placed on the table. For example, many users can acquire row share locks on a table at the same time, but only one user at a time can acquire an exclusive lock. While one user has an exclusive lock on a table, no other users can insert, delete, or update rows in that table. For more information about lock modes, see Oracle Database Application Developer's Guide - Fundamentals.

A table lock never keeps other users from querying a table, and a query never acquires a table lock. Only if two different transactions try to modify the same row will one transaction wait for the other to complete.

Fetching Across Commits

PL/SQL raises an exception if you try to fetch from a FOR UPDATE cursor after doing a commit. The FOR UPDATE clause locks the rows when you open the cursor, and unlocks them when you commit.

DECLARE

--if "FOR UPDATE OF salary" is included on following line, an error is raised CURSOR c1 IS SELECT * FROM employees;

emp_rec employees%ROWTYPE; BEGIN

OPEN c1;

Performing SQL Operations from PL/SQL 6-35

Overview of Transaction Processing in PL/SQL

LOOP

FETCH c1 INTO emp_rec; -- FETCH fails on the second iteration with FOR UPDATE EXIT WHEN c1%NOTFOUND;

IF emp_rec.employee_id = 105 THEN

UPDATE employees SET salary = salary * 1.05 WHERE employee_id = 105; END IF;

COMMIT; -- releases locks END LOOP;

END;

/

If you want to fetch across commits, use the ROWID pseudocolumn to mimic the CURRENT OF clause. Select the rowid of each row into a UROWID variable, then use the rowid to identify the current row during subsequent updates and deletes.

Example 6–42 Fetching Across COMMITs Using ROWID

DECLARE

CURSOR c1 IS SELECT last_name, job_id, rowid FROM employees; my_lastname employees.last_name%TYPE;

my_jobid employees.job_id%TYPE; my_rowid UROWID;

BEGIN

OPEN c1; LOOP

FETCH c1 INTO my_lastname, my_jobid, my_rowid; EXIT WHEN c1%NOTFOUND;

UPDATE employees SET salary = salary * 1.02 WHERE rowid = my_rowid; -- this mimics WHERE CURRENT OF c1

COMMIT; END LOOP; CLOSE c1;

END;

/

Because the fetched rows are not locked by a FOR UPDATE clause, other users might unintentionally overwrite your changes. The extra space needed for read consistency is not released until the cursor is closed, which can slow down processing for large updates.

The next example shows that you can use the %ROWTYPE attribute with cursors that reference the ROWID pseudocolumn:

DECLARE

CURSOR c1 IS SELECT employee_id, last_name, salary, rowid FROM employees; emp_rec c1%ROWTYPE;

BEGIN

OPEN c1; LOOP

FETCH c1 INTO emp_rec; EXIT WHEN c1%NOTFOUND;

IF emp_rec.salary = 0 THEN

DELETE FROM employees WHERE rowid = emp_rec.rowid; END IF;

END LOOP; CLOSE c1;

END;

/

6-36 Oracle Database PL/SQL User’s Guide and Reference

Соседние файлы в папке PL_SQL