Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 6 ■ LOCKING AND LATCHING 195 ops$tkyte@ORA10G> begin 2 for x in ( select deptno, dname, loc 3 from dept 4 where deptno = 10 5 for update nowait ) 6 loop 7 if ( hextoraw( 'C44F7052661CE945D385D5C3F911E70FA99407A6' ) 8 dbms_crypto.hash 9 ( utl_raw.cast_to_raw(x.deptno||'/'||x.dname||'/'||x.loc), 10 dbms_crypto.hash_sh1 ) ) 11 then 12 raise_application_error(-20001, 'Row was modified' ); 13 end if; 14 end loop; 15 update dept 16 set dname = lower(dname) 17 where deptno = 10; 18 commit; 19 end; 20 / PL/SQL procedure successfully completed. Upon requerying that data and computing the hash again after the update, we can see that the hash value is very different. If someone had modified the row before we did, our hash values would not have compared: ops$tkyte@ORA10G> begin 2 for x in ( select deptno, dname, loc 3 from dept 4 where deptno = 10 ) 5 loop 6 dbms_output.put_line( 'Dname: ' || x.dname ); 7 dbms_output.put_line( 'Loc: ' || x.loc ); 8 dbms_output.put_line( 'Hash: ' || 9 dbms_crypto.hash 10 ( utl_raw.cast_to_raw(x.deptno||'/'||x.dname||'/'||x.loc), 11 dbms_crypto.hash_sh1 ) ); 12 end loop; 13 end; 14 / Dname: accounting Loc: NEW YORK Hash: F3DE485922D44DF598C2CEBC34C27DD2216FB90F PL/SQL procedure successfully completed.
196 CHAPTER 6 ■ LOCKING AND LATCHING This example showed how to implement optimistic locking with a hash or checksum. You should bear in mind that computing a hash or checksum is a somewhat CPU-intensive operation—it is computationally expensive. On a system where CPU is a scarce resource, you must take this fact into consideration. However, this approach is much more “network-friendly,” as the transmission of a relatively small hash instead of a before and after image of the row (to compare column by column) over the network will consume much less of that resource. Our last example will use a new Oracle 10g function, ORA_ROWSCN, which is small in size like a hash, but not CPU intensive to compute. Optimistic Locking Using ORA_ROWSCN Starting with Oracle 10g Release 1, you have the option to use the built-in ORA_ROWSCN function. It works very much like the version column technique described previously, but it can be performed automatically by Oracle—you need no extra column in the table and no extra update/maintenance code to update this value. ORA_ROWSCN is based on the internal Oracle system clock, the SCN. Every time you commit in Oracle, the SCN advances (other things can advance it as well, but it only advances; it never goes back). The concept is identical to the previous methods in that you retrieve ORA_ROWSCN upon data retrieval, and you verify it has not changed when you go to update. The only reason I give it more than passing mention is that unless you created the table to support the maintenance of ORA_ROWSCN at the row level, it is maintained at the block level. That is, by default many rows on a single block will share the same ORA_ROWSCN value. If you update a row on a block with 50 other rows, then they will all have their ORA_ROWSCN advanced as well. This would almost certainly lead to many false positives, whereby you believe a row was modified that in fact was not. Therefore, you need to be aware of this fact and understand how to change the behavior. To see the behavior and then change it, we’ll use the small DEPT table again: ops$tkyte@ORA10G> create table dept 2 (deptno, dname, loc, data, 3 constraint dept_pk primary key(deptno) 4 ) 5 as 6 select deptno, dname, loc, rpad('*',3500,'*') 7 from scott.dept; Table created. Now we can inspect what block each row is on (it is safe to assume in this case they are in the same file, so a common block number indicates they are on the same block). I was using an 8KB block size with a row width of about 3,550 bytes, so I am expecting there to be two rows per block for this example: ops$tkyte@ORA10G> select deptno, dname, 2 dbms_rowid.rowid_block_number(rowid) blockno, 3 ora_rowscn 4 from dept;
- Page 190 and 191: CHAPTER 4 ■ MEMORY STRUCTURES 145
- Page 192 and 193: CHAPTER 4 ■ MEMORY STRUCTURES 147
- Page 194 and 195: CHAPTER 4 ■ MEMORY STRUCTURES 149
- Page 196 and 197: CHAPTER 4 ■ MEMORY STRUCTURES 151
- Page 198 and 199: CHAPTER 4 ■ MEMORY STRUCTURES 153
- Page 200 and 201: CHAPTER 5 ■ ■ ■ Oracle Proces
- Page 202 and 203: CHAPTER 5 ■ ORACLE PROCESSES 157
- Page 204 and 205: CHAPTER 5 ■ ORACLE PROCESSES 159
- Page 206 and 207: CHAPTER 5 ■ ORACLE PROCESSES 161
- Page 208 and 209: CHAPTER 5 ■ ORACLE PROCESSES 163
- Page 210 and 211: CHAPTER 5 ■ ORACLE PROCESSES 165
- Page 212 and 213: CHAPTER 5 ■ ORACLE PROCESSES 167
- Page 214 and 215: CHAPTER 5 ■ ORACLE PROCESSES 169
- Page 216 and 217: CHAPTER 5 ■ ORACLE PROCESSES 171
- Page 218 and 219: CHAPTER 5 ■ ORACLE PROCESSES 173
- Page 220 and 221: CHAPTER 5 ■ ORACLE PROCESSES 175
- Page 222 and 223: CHAPTER 5 ■ ORACLE PROCESSES 177
- Page 224 and 225: CHAPTER 5 ■ ORACLE PROCESSES 179
- Page 226 and 227: CHAPTER 5 ■ ORACLE PROCESSES 181
- Page 228 and 229: CHAPTER 6 ■ ■ ■ Locking and L
- Page 230 and 231: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 232 and 233: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 234 and 235: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 236 and 237: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 238 and 239: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 242 and 243: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 244 and 245: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 246 and 247: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 248 and 249: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 250 and 251: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 252 and 253: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 254 and 255: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 256 and 257: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 258 and 259: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 260 and 261: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 262 and 263: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 264 and 265: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 266 and 267: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 268 and 269: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 270 and 271: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 272 and 273: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 274 and 275: CHAPTER 6 ■ LOCKING AND LATCHING
- Page 276 and 277: CHAPTER 7 ■ ■ ■ Concurrency a
- Page 278 and 279: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 280 and 281: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 282 and 283: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 284 and 285: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 286 and 287: CHAPTER 7 ■ CONCURRENCY AND MULTI
- Page 288 and 289: CHAPTER 7 ■ CONCURRENCY AND MULTI
196<br />
CHAPTER 6 ■ LOCKING AND LATCHING<br />
This example showed how to implement optimistic locking with a hash or checksum. You<br />
should bear in mind that computing a hash or checksum is a somewhat CPU-intensive operation—it<br />
is computationally expensive. On a system where CPU is a scarce resource, you must<br />
take this fact into consideration. However, this approach is much more “network-friendly,” as<br />
the transmission of a relatively small hash instead of a before <strong>and</strong> after image of the row (to<br />
compare column by column) over the network will consume much less of that resource. Our<br />
last example will use a new <strong>Oracle</strong> 10g function, ORA_ROWSCN, which is small in size like a hash,<br />
but not CPU intensive to compute.<br />
Optimistic Locking Using ORA_ROWSCN<br />
Starting with <strong>Oracle</strong> 10g Release 1, you have the option to use the built-in ORA_ROWSCN function.<br />
It works very much like the version column technique described previously, but it can<br />
be performed automatically by <strong>Oracle</strong>—you need no extra column in the table <strong>and</strong> no extra<br />
update/maintenance code to update this value.<br />
ORA_ROWSCN is based on the internal <strong>Oracle</strong> system clock, the SCN. Every time you commit<br />
in <strong>Oracle</strong>, the SCN advances (other things can advance it as well, but it only advances; it never<br />
goes back). The concept is identical to the previous methods in that you retrieve ORA_ROWSCN<br />
upon data retrieval, <strong>and</strong> you verify it has not changed when you go to update. The only reason<br />
I give it more than passing mention is that unless you created the table to support the maintenance<br />
of ORA_ROWSCN at the row level, it is maintained at the block level. That is, by default<br />
many rows on a single block will share the same ORA_ROWSCN value. If you update a row on a<br />
block with 50 other rows, then they will all have their ORA_ROWSCN advanced as well. This would<br />
almost certainly lead to many false positives, whereby you believe a row was modified that in<br />
fact was not. Therefore, you need to be aware of this fact <strong>and</strong> underst<strong>and</strong> how to change the<br />
behavior.<br />
To see the behavior <strong>and</strong> then change it, we’ll use the small DEPT table again:<br />
ops$tkyte@ORA10G> create table dept<br />
2 (deptno, dname, loc, data,<br />
3 constraint dept_pk primary key(deptno)<br />
4 )<br />
5 as<br />
6 select deptno, dname, loc, rpad('*',3500,'*')<br />
7 from scott.dept;<br />
Table created.<br />
Now we can inspect what block each row is on (it is safe to assume in this case they are in<br />
the same file, so a common block number indicates they are on the same block). I was using<br />
an 8KB block size with a row width of about 3,550 bytes, so I am expecting there to be two<br />
rows per block for this example:<br />
ops$tkyte@ORA10G> select deptno, dname,<br />
2 dbms_rowid.rowid_block_number(rowid) blockno,<br />
3 ora_rowscn<br />
4 from dept;