Professional Documents
Culture Documents
AUTONOMOUS TRANSACTIONS
................................................................................
1
DESCRIPTION
...................................................................................................................
2
EXAMPLE – Autonomous Transaction
.............................................................................
3
PRAGMA EXCEPTION
................................................................................................
14
PRAGMA SERIALLY_REUSABLE
............................................................................
15
PRAGMA RESRTICTED_REFERENCE
....................................................................
17
AUTONOMOUS TRANSACTIONS
INTRO -
Before the release of PL/SQL 8.1, each Oracle session could have at most one
active transaction at a given time. In other words,any and all changes made in your
session had to be either saved or erased in their entirety. This restriction has long been
considered a drawback in the PL/SQL world. Developers have requested the ability to
execute and save or cancel certain DML statements (INSERT, UPDATE, DELETE)
without affecting the overall session’s transaction.
You can now accomplish this goal with the autonomous transaction feature of
PL/SQL 8.1 and above. When you define a PL/SQL block (anonymous block, procedure,
function, packaged procedure, packaged function, database trigger) as an autonomous
transaction, you isolate the DML in that block from the caller’s transaction context.
That block becomes an independent transaction that is started by another transaction,
referred to as the main transaction.
Within the autonomous transaction block, the main transaction is suspended. You perform
your SQL operations, commit or roll back those operations, and resume the main
transaction.
Syntax --
PRAGMA AUTONOMOUS_TRANSACTION;
The pragma instructs the PL/SQL compiler to establish a PL/SQL block as autonomous
or independent. For the purposes of the autonomous transaction, a PL/SQL block can be
any of the following:
1
You can put the autonomous transaction pragma anywhere in the declaration section of
your PL/SQL block. The best option, however, would be to place it before any data
structure declarations. That way, anyone reading your code will immediately identify the
program as an autonomous transaction.
This pragma is the only syntax change made to PL/SQL to support autonomous
transactions. COMMIT, ROLLBACK, the DML statements—all the rest is as it was
before. However, these statements have a different scope of impact and visibility when
executed within an autonomous transaction, and you will have to include a COMMIT or
ROLLBACK in your program.
DESCRIPTION
Usage Notes
You cannot use the pragma to mark all subprograms in a package (or all methods in an
object type) as autonomous. Only individual routines can be marked autonomous. You
can code the pragma anywhere in the declarative section of a routine. But, for readability,
code the pragma at the top of the section.
2
If you set the isolation level of the main transaction to SERIALIZABLE, as follows,
changes made by its autonomous transactions are not visible to the main transaction when
it resumes:
When in the main transaction, rolling back to a savepoint marked before you started an
autonomous transaction does not roll back the autonomous transaction. Remember,
autonomous transactions are fully independent of the main transaction.
If you try to exit an active autonomous transaction without committing or rolling back,
Oracle raises an exception. If the exception goes unhandled, the transaction is rolled
back.
Related Topics
In the example below, you mark a database trigger as autonomous. Unlike regular
triggers, autonomous triggers can contain transaction control statements.
3
CREATE TRIGGER parts_trigger
BEFORE INSERT ON parts FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO parts_log VALUES(:new.pnum, :new.pname);
COMMIT; -- allowed only in autonomous triggers
END;
******
You will want to define your program module as an autonomous transaction whenever
you want to isolate the changes made in that module from the caller’s transaction context.
Here are some specific ideas where autonomous transactions are useful:
Logging mechanism
This is the classic example of the need for an autonomous transaction. You need to log
error information in a database table, but don't want that log entry to be a part of the
logical transaction.
If you define a trigger as an autonomous transaction, then you can commit and/or roll
back in that code.
Retry counter
Autonomous transactions can help you keep track of how many times a user tries to
connect to a database or get access to a resource (you'll reject access after a certain
number of attempts).
You want to keep track of how often a program is called during an application session.
This information is not dependent on, and cannot affect, the transaction being processed
in the application.
It is becoming ever more important to be able to offer standalone units of work (also
known as cartridges) that get their job done without any side effects on the calling
environment. Autonomous transactions will play a crucial role in this area.
4
******
While it is certainly very easy to add the autonomous transaction pragma to your code,
there are some rules and restrictions on the use of this feature. You can only make a top-
level anonymous block an autonomous transaction. The following construction will
work:
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
myempno NUMBER;
BEGIN
INSERT INTO emp VALUES (myempno, ...);
COMMIT;
END;
/
DECLARE
myempno NUMBER;
BEGIN
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO emp VALUES (myempno, ...);
COMMIT;
END;
END;
/
You can now use COMMIT and ROLLBACK inside your database triggers. These
actions will not affect the transaction that caused the database trigger to fire.
5
CREATE OR REPLACE PROCEDURE
update_salary (dept_in IN NUMBER)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
CURSOR myemps IS
SELECT empno FROM emp
WHERE deptno = dept_in
FOR UPDATE NOWAIT;
BEGIN
FOR rec IN myemps
LOOP
UPDATE emp SET sal = sal * 2
WHERE empno = rec.empno;
END LOOP;
COMMIT;
END;
/
BEGIN
UPDATE emp SET sal = sal * 2;
update_salary (10);
END;
/
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified
You cannot mark all subprograms in a package (or all methods in an object type) as
autonomous with a single PRAGMA declaration. You must indicate autonomous
transactions explicitly in each program. For example, the following package specification
is invalid:
PROCEDURE register (
culprit IN VARCHAR2, event IN VARCHAR2);
END warcrimes_pkg;
/
6
One consequence of this rule is that you cannot tell by looking at the package
specification which, if any, programs will run as autonomous transactions.
To exit without errors from an autonomous transaction program, you must perform an
explicit commit or rollback. If the program (or any program called by it) has transactions
pending, the runtime engine will raise an exception—and then it will roll back those
uncommitted transactions.
Suppose, for example, that your job is to take over failing companies and make them
profitable by firing employees. You would then want to use this procedure:
You want to make the program an autonomous transaction because you don’t want
anyone to back out the changes when you are not looking. If you do not explicitly
commit, when you run this procedure, the following error occurs:
ERROR at line 1
ORA-06519: active autonomous transaction detected and rolled back
An autonomous block is one in which autonomous transactions are expected. Zero, one,
or more autonomous transactions can be executed within an autonomous block.
You can roll back only to savepoints marked in the current transaction. When you are in
an autonomous transaction you cannot roll back to a savepoint set in the main transaction.
If you try to do so, the runtime engine will raise this exception:
7
might exceed this number—and raise an exception—unless you raise the
TRANSACTIONS value. This is the error you will get if you encounter this problem:
Ever since Oracle 7.3, you have been able to call your own functions from within SQL—
provided that you follow a variety of rules. The main one is this: you are not allowed to
update the database. And you can’t save or cancel changes from within the function.
With the autonomous transaction feature, however, the picture changes. An autonomous
transaction program never violates the two database-related purity levels, RNDS (reads
no database state) and WNDS (writes no database state), even if that program actually
does read from or write to the database. This is because those purity levels or constraints
apply to the SQL statement (which, in this case, is the main transaction), yet an
autonomous transaction’s DML actions never affect the main transaction.
As long as you define a program to be an autonomous transaction, you can also call it
directly or indirectly in a SQL statement. If your program cannot assert another purity
level, such as WNPS (writes no package state), you may be restricted from calling that
program in certain parts of the SQL statement, such as the WHERE clause.
As an example, suppose that you want to keep a trace of all the rows that have been
touched by a query. This table is created:
8
/
When you try to use this function inside a query, you get the following error:
14 rows selected.
SQL>
You have other options when it comes to tracing queries: you can write to the
screen with the DBMS_OUTPUT built-in package or send information to a pipe with
DBMS_PIPE. Now that autonomous transactions are available, if you do want to send
information to a database table (or delete rows or update data, etc.), you can take that
route instead, but be sure to analyze carefully the overhead of this approach.
Transaction Visibility
9
The default behavior of autonomous transactions is that once a COMMIT or
ROLLBACK occurs in the autonomous transaction, those changes are visible
immediately in the main transaction. Oracle offers a SET TRANSACTION statement
option to hide those changes from the main transaction:
The default isolation level is READ COMMITTED, which means that as soon as changes
are committed, they are visible to the main transaction.
As is usually the case with the SET TRANSACTION statement, you must call it before
you initiate your transactions (i.e., issue any SQL statements); in addition, the setting
affects your entire session, not just the current program. The following script
demonstrates the SERIALIZABLE isolation level at work.
A script is run that sets the isolation level to SERIALIZABLE, then the number of rows
that appear in the emp2 table at the following times are displayed:
DECLARE
PROCEDURE showcount (str VARCHAR2) IS
num INTEGER;
BEGIN
SELECT COUNT(*) INTO num FROM emp2;
DBMS_OUTPUT.PUT_LINE (str || ' ' || num);
END;
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
showcount ('Before isolated AT delete');
fire_em_all;
showcount ('After isolated AT delete');
10
COMMIT;
showcount ('After MT commit');
END;
/
******************
You may want to take an action in the database trigger that is not affected by the ultimate
disposition of the transaction that caused the trigger to fire. For example, suppose that
you want to keep track of each action against a table, whether or not the action is
completed. You might even want to be able to detect which actions failed. You can use
autonomous transactions to do this.
Here is the before-insert trigger to run all the elements in the script:
11
BEFORE INSERT ON ceo_compensation FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO ceo_comp_history VALUES (
:new.name, 'BEFORE INSERT', SYSDATE);
COMMIT;
END;
/
With this trigger in place, every insert attempt can be tracked, as shown in the steps
below:
BEGIN
INSERT INTO ceo_compensation VALUES (
'Mattel', 'Jill Barad', 9100000, 2700);
But there is something of a problem with the trigger just defined. The trigger was defined
as an autonomous transaction because the alert was performed in the body of the trigger.
Suppose you want to perform some additional DML for the main transaction here in the
trigger. It won’t be rolled back with the rest of the transaction (if a rollback occurs).
12
Generally, it is recommended that you not make a database trigger itself the autonomous
transaction. Instead, push all of the independent DML activity (such as writing to the
audit or history table) into its own procedure. Make that procedure the autonomous
transaction. Have the trigger call the procedure.
• The trigger is now an after-insert trigger, rather than a before-insert trigger. Wait
until after the INSERT to the compensation table takes place, then perform the
audit.
13
• When the is_valid_comp_info function returns FALSE, do not even perform an
audit. Instead, stop the transaction by raising an error. This demonstrates the other
reason you don’t want the trigger itself to be autonomous. In some situations, you
will always want to perform an audit. Under other circumstances, however, you
may want to stop the main transaction by raising an exception. Both of those
events can't happen if the exception is raised in the same block and transaction as
the audit DML.
As you take advantage of the new autonomous transaction pragma, plan out how you will
be using these new code elements. You will almost always be better off hiding the details
of your new, independent transactions behind a procedural interface.
PRAGMA EXCEPTION
This allows specification of a handler to take care of any exceptions that result
from an Oracle error. If you don't specify the EXCEPTION_INIT clause, you must allow
for processing of non-specified exceptions in the OTHERS exception area.
The EXCEPTION_INIT clause must appear in the same declarative section as its
associated exception handler.
DECLARE
exception_name EXCEPTION;
PRAGMA EXCEPTION_INIT (exception_name, error_code_literal);
BEGIN
In the following program code, we declare and associate an exception for this error:
This error occurs if we try to delete a parent record while there are child records still in
that table. A child record is a record with a foreign key reference to the parent table:
14
PROCEDURE delete_company (company_id_in IN NUMBER)
IS
/* Declare the exception. */
still_have_employees EXCEPTION;
When you use EXCEPTION_INIT, you must supply a literal number for the second
argument of the pragma call. By explicitly naming this system exception, the purpose of
the exception handler is self-evident.
The EXCEPTION_INIT pragma improves the readability of your programs by assigning
names to otherwise obscure error numbers. You can employ the EXCEPTION_INIT
pragma more than once in your program. You can even assign more than one exception
name to the same error number.
***********
PRAGMA SERIALLY_REUSABLE
Prior to PL/SQL 8, any data declared in a package simply stayed around until the end of
the session, whether or not it was needed any more by the application. While this is an
important feature of PL/SQL packages (persistent, global data), it limits scalability since
such memory grows linearly with the number of users.
To help applications better manage memory usage, PL/SQL8 provides the pragma
SERIALLY_REUSABLE, which lets you mark some packages as "serially reusable."
You can so mark a package if its state is needed only for the duration of a call to the
server (for example, an OCI call to the server, a PL/SQL client-to-server, or server-to-
server RPC).
The global memory for such packages is not kept in the memory area per user, but instead
in a small SGA pool for reuse. Before reuse, the package global variables are initialized
to NULL or to the default values provided.
15
The pool is kept in SGA memory so that the work area of a package can be reused across
users who have requests for the same package. In this scheme, the maximum number of
work areas needed for a package is only as many as there are concurrent users of the
package, which is typically much fewer than the total number of logged on users. The
user of "serially reusable" packages does increase the shared-pool requirements slightly,
but this is more than offset by the decrease in the per-user memory requirements. Further,
Oracle ages out work areas not in use when it needs to reclaim shared pool memory.
Note: Use this feature with care. Many of your existing packages may absolutely rely on
the persistent data feature.
The keyword pragma signifies that the statement is a pragma (compiler directive).
Pragmas are processed at compile time, not at run time. They do not affect the meaning
of a program; they simply convey information to the compiler.
Example
The following example shows how global variables in a "serially reusable" package
behave across call boundaries:
16
/
Now we will exercise this package. First, we enable output from SQL*Plus:
Next, we initialize the package with a value of 4 and then display the package contents --
all within a single PL/SQL block:
SQLPLUS> begin
-- initialize and print the package
SR_PKG.init_pkg(4);
And we see that initial value of 4. If we had placed the call to SR_PKG.print_pkg inside
the same PL/SQL block, however, that package variable would lose its setting, as is
shown in the following steps:
SQLPLUS> begin
-- We should see that the package state is reset to the
-- initial (default) values.
SR_PKG.print_pkg;
end;
/
Statement processed.
num: 0
PRAGMA RESRTICTED_REFERENCE
When a stand alone user defined function is used in a SQL statement, there is no
guarantee that the function does not update the database. This guarantee can be made by:
Inspecting the code, or by Executing a SQL statement with the function. If the SQL parse
identifies an INSERT, UPDATE, or DELETE, the execution will fail. You do not have to
execute the specific path for the statement to fail. If the code contains ANY table
modification SQL, you will know it.
If user defined functions are used to any extent it is advisable to encapsulate them within
a package and designate this package as “pure”, that is, the functions in the package do
not modify the database. The “purity” of the package is denoted with the PL/SQL
17
pragma: RESTRICT_REFERENCES. This pragma has one mandatory argument and
three optional arguments. The optional arguments define the level of the “purity” of the
function.
RNDS - This asserts that the function reads no database state (does not query database
tables).
WNDS - This asserts that the function writes no database state (does not modify database
tables).
RNPS - This asserts that the function reads no package state (does not reference the
values of packaged variables)
WNPS - This asserts that the function writes no package state (does not change the values
of packaged variables).
TRUST - This asserts that the function can be trusted not to violate one or more rules.
Usage Notes
You can declare the pragma RESTRICT_REFERENCES only in a package spec or object
type spec. You can specify up to four constraints (RNDS, RNPS, WNDS, WNPS) To call
the function from parallel queries, you must specify all four constraints. No constraint
implies another. For example, WNPS does not imply RNPS.
When you specify TRUST, the function body is not checked for violations of the
constraints listed in the pragma. The function is trusted not to violate them.
If you specify DEFAULT instead of a function name, the pragma applies to all functions
in the package spec or object type spec (including, in the latter case, the system-defined
constructor). You can still declare the pragma for individual functions. Such pragmas
override the default pragma.
The following code segment illustrates a package that provides procedures and functions
in employee data and uses the pragma RESTRICT_REFERENCES.
18
-- returns the ROUNDED salary of the employee
pragma restrict_references(round_salary, WNDS);
end emp_pkg;
==================================THE END====================
19