Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 19 select count(*) into l_cnt from schedules where resource_name = p_resource_name and (start_time = p_start_time); if ( l_cnt 0 ) then raise_application_error (-20001, 'Room is already booked!' ); end if; If we get to this point in the code without raising an error, we can safely insert rows for our resource into the SCHEDULES table without any overlaps: insert into schedules ( resource_name, start_time, end_time ) values ( p_resource_name, p_start_time, p_end_time ); end schedule_resources; This solution is still highly concurrent, as there are potentially thousands of resources to be reserved. What we have done is ensure that only one person modifies a resource at any time. This is a rare case where the manual locking of data we are not going to actually update is called for. We need to be able to recognize where we need to do this and, perhaps as important, where we do not need to do this (I present an example of when not to shortly). Additionally, this does not lock the resource from other people reading the data as it might in other databases, hence this solution will scale very well. Issues such as the one described in this section have massive implications when you’re attempting to port an application from database to database (I return to this theme a little later in the chapter), and this trips people up time and time again. For example, if you are experienced in other databases where writers block readers and vice versa, then you may have grown reliant on that fact to protect you from data integrity issues. The lack of concurrency is one way to protect yourself from this—that is how it works in many non-Oracle databases. In Oracle, concurrency rules supreme and you must be aware that, as a result, things will happen differently (or suffer the consequences). ■Note We will revisit this example again in Chapter 7. The code as provided works under the assumption the transaction isolation level is READ COMMITTED. The logic will not work properly in SERIALIZABLE transaction isolations. Rather than complicate this chapter with the differences between those two modes, I defer that discussion until later. Ninety-nine percent of the time, locking is totally transparent and you need not concern yourself with it. It is that other 1 percent that you must be trained to recognize. There is no
20 CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS simple checklist of “If you do this, you need to do this” for this issue. It is a matter of understanding how your application will behave in a multiuser environment and how it will behave in your database. Chapter 7 delves into this topic in much more depth. There you will learn that integrity constraint enforcement of the type presented in this section, where we must enforce a rule that crosses multiple rows in a single table or is between two or more tables (like a referential integrity constraint), are cases where we must always pay special attention and will most likely have to resort to manual locking or some other technique to ensure integrity in a multiuser environment. Multi-Versioning This topic is very closely related to concurrency control, as it forms the foundation for Oracle’s concurrency control mechanism—Oracle operates a multi-version, read-consistent concurrency model. Again, in Chapter 7, we’ll cover the technical aspects of this in more detail but, essentially, it is the mechanism by which Oracle provides for the following: • Read-consistent queries: Queries that produce consistent results with respect to a point in time. • Non-blocking queries: Queries are never blocked by writers of data, as they would be in other databases. These are two very important concepts in the Oracle database. The term multi-versioning basically describes Oracle’s ability to simultaneously materialize multiple versions of the data from the database. If you understand how multi-versioning works, you will always understand the answers you get from the database. Before we explore in a little more detail how Oracle implements multi-versioning, here is the simplest way I know to demonstrate multi-versioning in Oracle: ops$tkyte@ORA10G> create table t 2 as 3 select * 4 from all_users; Table created. ops$tkyte@ORA10G> variable x refcursor ops$tkyte@ORA10G> begin 2 open :x for select * from t; 3 end; 4 / PL/SQL procedure successfully completed. ops$tkyte@ORA10G> delete from t; 28 rows deleted. ops$tkyte@ORA10G> commit; Commit complete.
- Page 14 and 15: ■FOREWORD xiii Tom is an aficiona
- Page 16 and 17: About the Technical Reviewers ■JO
- Page 18 and 19: Introduction The inspiration for th
- Page 20 and 21: ■INTRODUCTION xix • Exposure to
- Page 22 and 23: ■INTRODUCTION xxi Chapter 3: File
- Page 24 and 25: ■INTRODUCTION xxiii Next up are t
- Page 26 and 27: Setting Up Your Environment In this
- Page 28 and 29: ■SETTING UP YOUR ENVIRONMENT xxvi
- Page 30 and 31: ■SETTING UP YOUR ENVIRONMENT xxix
- Page 32 and 33: ■SETTING UP YOUR ENVIRONMENT xxxi
- Page 34 and 35: ■SETTING UP YOUR ENVIRONMENT xxxi
- Page 36 and 37: ■SETTING UP YOUR ENVIRONMENT xxxv
- Page 38 and 39: ■SETTING UP YOUR ENVIRONMENT xxxv
- Page 40 and 41: ■SETTING UP YOUR ENVIRONMENT xxxi
- Page 42 and 43: ■SETTING UP YOUR ENVIRONMENT xli
- Page 44 and 45: ■SETTING UP YOUR ENVIRONMENT xlii
- Page 46 and 47: CHAPTER 1 ■ ■ ■ Developing Su
- Page 48 and 49: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 50 and 51: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 52 and 53: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 54 and 55: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 56 and 57: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 58 and 59: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 60 and 61: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 62 and 63: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 66 and 67: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 68 and 69: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 70 and 71: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 72 and 73: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 74 and 75: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 76 and 77: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 78 and 79: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 80 and 81: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 82 and 83: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 84 and 85: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 86 and 87: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 88 and 89: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 90 and 91: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 92: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 95 and 96: 50 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 97 and 98: 52 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 99 and 100: 54 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 101 and 102: 56 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 103 and 104: 58 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 105 and 106: 60 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 107 and 108: 62 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 110 and 111: CHAPTER 3 ■ ■ ■ Files In this
- Page 112 and 113: CHAPTER 3 ■ FILES 67 Without a pa
CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 19<br />
select count(*)<br />
into l_cnt<br />
from schedules<br />
where resource_name = p_resource_name<br />
<strong>and</strong> (start_time = p_start_time);<br />
if ( l_cnt 0 )<br />
then<br />
raise_application_error<br />
(-20001, 'Room is already booked!' );<br />
end if;<br />
If we get to this point in the code without raising an error, we can safely insert rows for<br />
our resource into the SCHEDULES table without any overlaps:<br />
insert into schedules<br />
( resource_name, start_time, end_time )<br />
values<br />
( p_resource_name, p_start_time, p_end_time );<br />
end schedule_resources;<br />
This solution is still highly concurrent, as there are potentially thous<strong>and</strong>s of resources to<br />
be reserved. What we have done is ensure that only one person modifies a resource at any<br />
time. This is a rare case where the manual locking of data we are not going to actually update<br />
is called for. We need to be able to recognize where we need to do this <strong>and</strong>, perhaps as<br />
important, where we do not need to do this (I present an example of when not to shortly).<br />
Additionally, this does not lock the resource from other people reading the data as it might<br />
in other databases, hence this solution will scale very well.<br />
Issues such as the one described in this section have massive implications when you’re<br />
attempting to port an application from database to database (I return to this theme a little<br />
later in the chapter), <strong>and</strong> this trips people up time <strong>and</strong> time again. For example, if you are<br />
experienced in other databases where writers block readers <strong>and</strong> vice versa, then you may have<br />
grown reliant on that fact to protect you from data integrity issues. The lack of concurrency is<br />
one way to protect yourself from this—that is how it works in many non-<strong>Oracle</strong> databases. In<br />
<strong>Oracle</strong>, concurrency rules supreme <strong>and</strong> you must be aware that, as a result, things will happen<br />
differently (or suffer the consequences).<br />
■Note We will revisit this example again in Chapter 7. The code as provided works under the assumption<br />
the transaction isolation level is READ COMMITTED. The logic will not work properly in SERIALIZABLE transaction<br />
isolations. Rather than complicate this chapter with the differences between those two modes, I defer<br />
that discussion until later.<br />
Ninety-nine percent of the time, locking is totally transparent <strong>and</strong> you need not concern<br />
yourself with it. It is that other 1 percent that you must be trained to recognize. There is no