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.

34<br />

CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS<br />

This issue is compounded by the fact that our transaction is much larger than just outlined.<br />

The UPDATE <strong>and</strong> SELECT in the example are only two statements of potentially many<br />

other statements that make up our transaction. We have yet to insert the row into the table<br />

with this key we just generated <strong>and</strong> do whatever other work it takes to complete this transaction.<br />

This serialization will be a huge limiting factor in scaling. Think of the ramifications if<br />

this technique were used on web sites that process orders, <strong>and</strong> this was how we generated<br />

order numbers. There would be no multiuser concurrency, so we would be forced to do everything<br />

sequentially.<br />

The correct approach to this problem is to use the best code for each database. In <strong>Oracle</strong>,<br />

this would be (assuming the table that needs the generated primary key is T) as follows:<br />

create table t ( pk number primary key, ... );<br />

create sequence t_seq;<br />

create trigger t_trigger before insert on t for each row<br />

begin<br />

select t_seq.nextval into :new.pk from dual;<br />

end;<br />

This will have the effect of automatically—<strong>and</strong> transparently—assigning a unique key to<br />

each row inserted. A more performance driven approach would be simply<br />

Insert into t ( pk, ... ) values ( t_seq.NEXTVAL, ... );<br />

That is, skip the overhead of the trigger altogether (this is my preferred approach).<br />

In the first example, we’ve gone out of our way to use each database’s feature to generate<br />

a non-blocking, highly concurrent unique key, <strong>and</strong> we’ve introduced no real changes to the<br />

application code—all of the logic is contained in this case in the DDL.<br />

■Tip The same effect can be achieved in the other databases using their built-in features or generating<br />

unique numbers. The CREATE TABLE syntax may be different, but the net results will be the same.<br />

Once you underst<strong>and</strong> that each database will implement features in a different way,<br />

another example of defensive programming to allow for portability is to layer your access to<br />

the database when necessary. For example, say you are programming using JDBC. If all you<br />

use is straight SQL SELECTs, INSERTs, UPDATEs, <strong>and</strong> DELETEs, you probably do not need a layer of<br />

abstraction. You may very well be able to code the SQL directly in your application, as long as<br />

you limit the constructs you use to those supported by each of the databases you intend to<br />

support—<strong>and</strong> that you have verified work exactly the same (remember the NULL=NULL discussion!).<br />

Another approach that is both more portable <strong>and</strong> offers better performance is to use<br />

stored procedures to return resultsets. You will discover that every vendor’s database can<br />

return resultsets from stored procedures, but how they are returned is different. The actual<br />

source code you must write is different for different databases.<br />

Your two choices here are either to not use stored procedures to return resultsets or to<br />

implement different code for different databases. I would definitely follow the different code

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

Saved successfully!

Ooh no, something went wrong!