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 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 17<br />

encounter data integrity issues. (This is particularly common when developers move from<br />

another database to <strong>Oracle</strong>, or vice versa, <strong>and</strong> neglect to take the differing concurrency mechanisms<br />

into account in their application.)<br />

Preventing Lost Updates<br />

One of the side effects of <strong>Oracle</strong>’s non-blocking approach is that if you actually want to ensure<br />

that no more than one user has access to a row at once, then you, the developer, need to do a<br />

little work yourself.<br />

Consider the following example. A developer was demonstrating to me a resourcescheduling<br />

program (for conference rooms, projectors, etc.) that he had just developed <strong>and</strong><br />

was in the process of deploying. The application implemented a business rule to prevent the<br />

allocation of a resource to more than one person, for any given period of time. That is, the<br />

application contained code that specifically checked that no other user had previously allocated<br />

the time slot (as least, the developer thought it did). This code queried the SCHEDULES<br />

table <strong>and</strong>, if no rows existed that overlapped that time slot, inserted the new row. So, the developer<br />

was basically concerned with two tables:<br />

create table resources ( resource_name varchar2(25) primary key, ... );<br />

create table schedules<br />

( resource_name references resources,<br />

start_time date not null,<br />

end_time date not null,<br />

check (start_time < end_time ),<br />

primary key(resource_name,start_time)<br />

);<br />

And, before making, say, a room reservation, the application would query:<br />

select count(*)<br />

from schedules<br />

where resource_name = :room_name<br />

<strong>and</strong> (start_time = :new_start_time)<br />

It looked simple <strong>and</strong> bulletproof (to the developer anyway): if the count came back as<br />

zero, the room was yours. If it came back as nonzero, you could not reserve the room for that<br />

period. Once I knew what his logic was, I set up a very simple test to show him the error that<br />

would occur when the application went live—an error that would be incredibly hard to track<br />

down <strong>and</strong> diagnose after the fact. Someone would be convinced it must be a database bug.<br />

All I did was get someone else to use the terminal next to him. Both he <strong>and</strong> the other person<br />

navigated to the same screen <strong>and</strong>, on the count of three, each clicked the Go button <strong>and</strong><br />

tried to reserve the same room for about the same time—one from 3:00 pm to 4:00 pm <strong>and</strong> the<br />

other from 3:30 pm to 4:00 pm. Both people got the reservation. The logic that worked perfectly<br />

in isolation failed in a multiuser environment. The problem in this case was caused in<br />

part by <strong>Oracle</strong>’s non-blocking reads. Neither session ever blocked the other session. Both sessions<br />

simply ran the query <strong>and</strong> then performed the logic to schedule the room. They could<br />

both run the query to look for a reservation, even if the other session had already started to

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

Saved successfully!

Ooh no, something went wrong!