Está en la página 1de 9

Autonomous Transactions

Autonomous transactions allow you to leave the context of the calling transaction, perform an independant transaction, and return to the calling transaction without affecting it's state. The autonomous transaction has no link to the calling transaction, so only commited data can be shared by both transactions. The following types of PL/SQL blocks can be defined as autonomous transactions:

Stored procedures and functions. Local procedures and functions defined in a PL/SQL declaration block. Packaged procedures and functions. Type methods. Top-level anonymous blocks.

The easiest way to understand autonomous transactions is to see them in action. To do this, we create a test table and populate it with two rows. Notice that the data is not commited.

CREATE TABLE at_test ( id NUMBER NOT NULL, description VARCHAR2(50) NOT NULL ); INSERT INTO at_test (id, description) VALUES (1, 'Description for 1'); INSERT INTO at_test (id, description) VALUES (2, 'Description for 2'); SELECT * FROM at_test; ID ---------1 2 DESCRIPTION -------------------------------------------------Description for 1 Description for 2

2 rows selected. SQL>


Next, we insert another 8 rows using an anonymous block declared as an autonomous transaction, which contains a commit statement.

DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN FOR i IN 3 .. 10 LOOP INSERT INTO at_test (id, description) VALUES (i, 'Description for ' || i); END LOOP; COMMIT; END; / PL/SQL procedure successfully completed. SELECT * FROM at_test;

ID ---------1 2 3 4 5 6 7 8 9 10

DESCRIPTION -------------------------------------------------Description for 1 Description for 2 Description for 3 Description for 4 Description for 5 Description for 6 Description for 7 Description for 8 Description for 9 Description for 10

10 rows selected. SQL>


As expected, we now have 10 rows in the table. If we now issue a rollback statement we get the following result.

ROLLBACK; SELECT * FROM at_test; ID ---------3 4 5 6 7 8 9 10 DESCRIPTION -------------------------------------------------Description for 3 Description for 4 Description for 5 Description for 6 Description for 7 Description for 8 Description for 9 Description for 10

8 rows selected. SQL>


The 2 rows inserted by our current session (transaction) have been rolled back, while the rows inserted by the autonomous transactions remain. The presence of the PRAGMA AUTONOMOUS_TRANSACTION compiler directive made the anonymous block run in its own transaction, so the internal commit statement did not affect the calling session. As a result rollback was still able to affect the DML issued by the current statement. Autonomous transactions are commonly used by error logging routines, where the error messages must be preserved, regardless of the the commit/rollback status of the transaction. For example, the following table holds basic error messages.

CREATE TABLE error_logs ( id NUMBER(10) NOT NULL, log_timestamp TIMESTAMP NOT NULL, error_message VARCHAR2(4000), CONSTRAINT error_logs_pk PRIMARY KEY (id) );

CREATE SEQUENCE error_logs_seq;


We define a procedure to log error messages as an autonomous transaction.

CREATE OR REPLACE PROCEDURE log_errors (p_error_message IN VARCHAR2) AS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN INSERT INTO error_logs (id, log_timestamp, error_message) VALUES (error_logs_seq.NEXTVAL, SYSTIMESTAMP, p_error_message); COMMIT; END; /
The following code forces an error, which is trapped and logged.

BEGIN INSERT INTO at_test (id, description) VALUES (998, 'Description for 998'); -- Force invalid insert. INSERT INTO at_test (id, description) VALUES (999, NULL); EXCEPTION WHEN OTHERS THEN log_errors (p_error_message => SQLERRM); ROLLBACK; END; / PL/SQL procedure successfully completed. SELECT * FROM at_test WHERE id >= 998; no rows selected SELECT * FROM error_logs; ID LOG_TIMESTAMP ---------- -------------------------------------------------------------------------ERROR_MESSAGE --------------------------------------------------------------------------------------------------1 28-FEB-2006 11:10:10.107625 ORA-01400: cannot insert NULL into ("TIM_HALL"."AT_TEST"."DESCRIPTION") 1 row selected.

Overview of Autonomous Transactions

Autonomous transactions are independent transactions that can be called from within another transaction. An autonomous transaction lets you leave the context of the calling transaction, perform some SQL operations, commit or undo those operations, and then return to the calling transaction's context and continue with that transaction. Once invoked, an autonomous transaction is totally independent of the main transaction that called it. It does not see any of the uncommitted changes made by the main transaction and does not share any locks or resources with the main transaction. Changes made by an autonomous transaction become visible to other transactions upon commit of the autonomous transactions. One autonomous transaction can call another. There are no limits, other than resource limits, on how many levels of autonomous transactions can be called. Deadlocks are possible between an autonomous transaction and its calling transaction. Oracle detects such deadlocks and returns an error. The application developer is responsible for avoiding deadlock situations. Autonomous transactions are useful for implementing actions that need to be performed independently, regardless of whether the calling transaction commits or rolls back, such as transaction logging and retry counters.
Autonomous PL/SQL Blocks

You can call autonomous transactions from within a PL/SQL block. Use the pragma AUTONOMOUS_TRANSACTION. A pragma is a compiler directive. You can declare the following kinds of PL/SQL blocks to be autonomous:

Stored procedure or function Local procedure or function Package Type method Top-level anonymous block

When an autonomous PL/SQL block is entered, the transaction context of the caller is suspended. This operation ensures that SQL operations performed in this block (or other blocks called from it) have no dependence or effect on the state of the caller's transaction context. When an autonomous block invokes another autonomous block or itself, the called block does not share any transaction context with the calling block. However, when an autonomous block invokes a non-autonomous block (that is, one that is not declared to

be autonomous), the called block inherits the transaction context of the calling autonomous block.
Transaction Control Statements in Autonomous Blocks

Transaction control statements in an autonomous PL/SQL block apply only to the currently active autonomous transaction. Examples of such statements are:
SET TRANSACTION COMMIT ROLLBACK SAVEPOINT ROLLBACK TO SAVEPOINT

Similarly, transaction control statements in the main transaction apply only to that transaction and not to any autonomous transaction that it calls. For example, rolling back the main transaction to a savepoint taken before the beginning of an autonomous transaction does not undo the autonomous transaction. See Also:

Introduction to REF CURSOR A REF CURSOR is basically a data type. A variable created based on such a data type is generally called a cursor variable. A cursor variable can be associated with different queries at run-time. The primary advantage of using cursor variables is their capability to pass result sets between sub programs (like stored procedures, functions, packages etc.). Let us start with a small sub-program as follows: declare type r_cursor is REF CURSOR; c_emp r_cursor; en emp.ename%type; begin open c_emp for select ename from emp; loop fetch c_emp into en; exit when c_emp%notfound; dbms_output.put_line(en); end loop;

close c_emp; end; Let me explain step by step. The following is the first statement you need to understand: type r_cursor is REF CURSOR; The above statement simply defines a new data type called "r_cursor," which is of the type REF CURSOR. We declare a cursor variable named "c_emp" based on the type "r_cursor" as follows: c_emp r_cursor; Every cursor variable must be opened with an associated SELECT statement as follows: open c_emp for select ename from emp; To retrieve each row of information from the cursor, I used a loop together with a FETCH statement as follows: loop fetch c_emp into en; exit when c_emp%notfound; dbms_output.put_line(en); end loop; I finally closed the cursor using the following statement: close c_emp; %ROWTYPE with REF CURSOR In the previous section, I retrieved only one column (ename) of information using REF CURSOR. Now I would like to retrieve more than one column (or entire row) of information using the same. Let us consider the following example: declare type r_cursor is REF CURSOR; c_emp r_cursor;

er emp%rowtype; begin open c_emp for select * from emp; loop fetch c_emp into er; exit when c_emp%notfound; dbms_output.put_line(er.ename || ' - ' || er.sal); end loop; close c_emp; end; In the above example, the only crucial declaration is the following: er emp%rowtype; The above declares a variable named "er," which can hold an entire row from the "emp" table. To retrieve the values (of each column) from that variable, we use the dot notation as follows: dbms_output.put_line(er.ename || ' - ' || er.sal); Let us consider that a table contains forty columns and I would like to retrieve fifteen columns. In such scenarios, it is a bad idea to retrieve all forty columns of information. At the same time, declaring and working with fifteen variables would be bit clumsy. The next section will explain how to solve such issues.

What is Normalization? Normalization is the process of efficiently organizing data in a database. There are two goals of the normalization process: eliminating redundant data (for example, storing the same data in more than one table) and ensuring data dependencies make sense (only storing related data in a table). Both of these are worthy goals as they reduce the amount of space a database consumes and ensure that data is logically stored. The Normal Forms The database community has developed a series of guidelines for ensuring that databases are normalized. These are referred to as normal forms and are numbered from one (the lowest form of normalization, referred to as first normal form or 1NF) through five (fifth normal form or

5NF). In practical applications, you'll often see 1NF, 2NF, and 3NF along with the occasional 4NF. Fifth normal form is very rarely seen and won't be discussed in this article. Before we begin our discussion of the normal forms, it's important to point out that they are guidelines and guidelines only. Occasionally, it becomes necessary to stray from them to meet practical business requirements. However, when variations take place, it's extremely important to evaluate any possible ramifications they could have on your system and account for possible inconsistencies. That said, let's explore the normal forms. First Normal Form (1NF) First normal form (1NF) sets the very basic rules for an organized database:

Eliminate duplicative columns from the same table. Create separate tables for each group of related data and identify each row with a unique column or set of columns (the primary key). For more details, read Putting your Database in First Normal Form Second Normal Form (2NF) Second normal form (2NF) further addresses the concept of removing duplicative data:

Meet all the requirements of the first normal form. Remove subsets of data that apply to multiple rows of a table and place them in separate tables. Create relationships between these new tables and their predecessors through the use of foreign keys. For more details, read Putting your Database in Second Normal Form Third Normal Form (3NF) Third normal form (3NF) goes one large step further:

Meet all the requirements of the second normal form. Remove columns that are not dependent upon the primary key. For more details, read Putting your Database in Third Normal Form Boyce-Codd Normal Form (BCNF or 3.5NF) The Boyce-Codd Normal Form, also referred to as the "third and half (3.5) normal form", adds one more requirement:

Meet all the requirements of the third normal form. Every determinant must be a candidate key. For more details, read Putting your Database in Boyce Codd Normal Form Fourth Normal Form (4NF) Finally, fourth normal form (4NF) has one additional requirement:

Meet all the requirements of the third normal form. A relation is in 4NF if it has no multi-valued dependencies. Remember, these normalization guidelines are cumulative. For a database to be in 2NF, it must first fulfill all the criteria of a 1NF database.