05.11.2015 Views

Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

CHAPTER 8 ■ TRANSACTIONS 259<br />

So, one row was successfully inserted into T <strong>and</strong> we duly received the message, I fired<br />

<strong>and</strong> updated 1 rows. The next INSERT statement violates the integrity constraint we have on T.<br />

The DBMS_OUTPUT message appeared—the trigger on T in fact did fire <strong>and</strong> we have evidence of<br />

that. It performed its updates of T2 successfully. We would maybe expect T2 to have a value of<br />

2 now, but we see it has a value of 1. <strong>Oracle</strong> made the original INSERT atomic—the original<br />

INSERT INTO T is the statement, <strong>and</strong> any side effects of that original INSERT INTO T are considered<br />

part of that statement.<br />

<strong>Oracle</strong> achieves this statement-level atomicity by silently wrapping a SAVEPOINT around<br />

each of our calls to the database. The preceding two INSERTs were really treated like this:<br />

Savepoint statement1;<br />

Insert into t values ( 1 );<br />

If error then rollback to statement1;<br />

Savepoint statement2;<br />

Insert into t values ( -1 );<br />

If error then rollback to statement2;<br />

For programmers used to Sybase or SQL Server, this may be confusing at first. In those<br />

databases exactly the opposite is true. The triggers in those systems execute independently of<br />

the firing statement. If they encounter an error, the triggers must explicitly roll back their own<br />

work <strong>and</strong> then raise another error to roll back the triggering statement. Otherwise, the work<br />

done by a trigger could persist even if the triggering statement, or some other part of the statement,<br />

ultimately fails.<br />

In <strong>Oracle</strong>, this statement-level atomicity extends as deep as it needs to. If in the preceding<br />

example, the INSERT INTO T fires a trigger that updates another table, <strong>and</strong> that table has a trigger<br />

that deletes from another table (<strong>and</strong> so on, <strong>and</strong> so on), either all of the work succeeds or<br />

none of it does. You do not need to code anything special to ensure this—it is just the way it<br />

works.<br />

Procedure-Level Atomicity<br />

It is interesting to note that <strong>Oracle</strong> considers PL/SQL anonymous blocks to be statements as<br />

well. Consider the following stored procedure:<br />

ops$tkyte@ORA10G> create or replace procedure p<br />

2 as<br />

3 begin<br />

4 insert into t values ( 1 );<br />

5 insert into t values (-1 );<br />

6 end;<br />

7 /<br />

Procedure created.<br />

ops$tkyte@ORA10G> select * from t;<br />

no rows selected<br />

ops$tkyte@ORA10G> select * from t2;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!