ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 关于oracle锁的笔记

关于oracle锁的笔记

原创 Linux操作系统 作者:阿日 时间:2008-09-17 09:22:38 0 删除 编辑
是看TOM的oracle10g编程艺术时边看边写的,写下来提醒一下自个儿

1.什么是锁?
  锁机制用于对于共享资源的并发访问,在数据库中还提供数据的完整性和一致性.
2.丢失更新问题?
  悲观锁定
  乐观锁定

对于悲观锁定,利用for update nowait来防止其它的用户来更新锁定的数据,这时在for update nowait中的where条件与另一用户update的语句的where 条件应该没有被更改,否则仍会更新记录,如下:
第一种情况:
用户1-SQLPLUS
SQL>  select empno,ename,sal
  2   from emp
  3   where empno=:empno
  4   and ename=:ename
  5   and sal=:sal
  6   for update nowait
  7  /

     EMPNO ENAME             SAL
---------- ---------- ----------
      7934 MILLER           1400

SQL> update emp set sal=1300 where empno=7934;

已更新 1 行。

SQL> commit; --当提交后,用户2的操作也会继续执行,否则一直在等待.

提交完成。

SQL>
用户2-SQLPLUS
SQL> update emp set sal=1350 where empno=7934 and ename='MILLER' and sal=1400
  2  /

已更新0行。
第二种情况
用户1-SQLPLUS
SQL>  select empno,ename,sal
  2   from emp
  3   where empno=:empno
  4   and ename=:ename
  5   for update nowait;

     EMPNO ENAME             SAL
---------- ---------- ----------
      7934 MILLER           1300

SQL> commit;
用户2-SQLPLUS
SQL> update emp set sal=1350 where empno=7934 and ename='MILLER' and sal=1300;

已更新0行。


乐观锁定:三种方法
1.采用一个时间戳即版本列
SQL>  create table detp1
  2   (deptno number(2),
  3   dname varchar2(14),
  4   loc varchar2(13),
  5   last_mod timestamp with time zone
  6   default systimestamp
  7   not null,
  8   constraint dept1_pk primary key(deptno)
  9  )
 10  /

SQL> variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable last_mod varchar2(50)
SQL> begin
  2    :deptno:=10;
  3    select dname,loc,last_mod
  4    into :dname,:loc,:last_mod
  5    from detp1
  6    where deptno=:deptno;
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL> select :deptno dno,:dname dname,:loc loc,:last_mod lm
  2  from dual;

       DNO DNAME                            LOC                              LM
---------- -------------------------------- -------------------------------- -----------------------
        10 ACCOUNTING                       NEW YORK                         10-SEP-08 10.53.51.406000 AM +08:00

SQL> update detp1
  2  set dname=initcap(:dname),
  3  last_mod=systimestamp
  4  where deptno=:deptno
  5  and last_mod=to_timestamp_tz(:last_mod);

1 row updated.

SQL>  update detp1
  2   set dname=initcap(:dname),
  3   last_mod=systimestamp
  4   where deptno=:deptno
  5   and last_mod=to_timestamp_tz(:last_mod);

0 rows updated.
2.使用校验和或散列函数
需要注意,单向散列函数只能在一个方向上应用。从输入数据计算散列值很容易,但是要生成能散列为某个特定值的数据却很难

3.利用ORA_ROWSCN来实现

一个数据块上的ORA_ROWSCN可能是相同的.
SQL>  create table dept1
  2   (deptno,dname,loc,data,
  3    constraint dept1_pk primary key(deptno)
  4   )
  5   as
  6   select deptno,dname,loc,rpad('*',3500,'*')
  7   from dept;

Table created.
以上可以看来,这些数据都在不同的块上,但ora_rowscn却相同
SQL> select deptno,dname,
  2  dbms_rowid.rowid_block_number(rowid) blockno,
  3  ora_rowscn
  4  from dept1;

    DEPTNO DNAME             BLOCKNO ORA_ROWSCN
---------- -------------- ---------- ----------
        10 ACCOUNTING           6484   12189086
        20 RESEARCH             6484   12189086
        30 SALES                6485   12189086
        40 OPERATIONS           6485   12189086

下面更新一个块上的数据,则此块上的其它数据的ora_rowscn也是变化的
SQL> update dept1 set dname=lower(dname)
  2  where deptno=10;

1 row updated.

SQL> commit;

Commit complete.

SQL> select deptno,dname,
  2  dbms_rowid.rowid_block_number(rowid) blockno,
  3  ora_rowscn
  4  from dept1;

    DEPTNO DNAME             BLOCKNO ORA_ROWSCN
---------- -------------- ---------- ----------
        10 accounting           6484   12189236
        20 RESEARCH             6484   12189236
        30 SALES                6485   12189086
        40 OPERATIONS           6485   12189086

启用属性rowdependencies.
SQL> create table dept1
  2  (deptno,dname,loc,data,
  3  constraint dept1_pk primary key(deptno)
  4  )
  5  rowdependencies
  6  as
  7  select deptno,dname,loc,rpad('*',3500,'*')
  8  from dept;

Table created.
SQL> select deptno,dname,
  2  dbms_rowid.rowid_block_number(rowid) blockno,
  3  ora_rowscn
  4  from dept1;

    DEPTNO DNAME             BLOCKNO ORA_ROWSCN
---------- -------------- ---------- ----------
        10 ACCOUNTING           6500   12189466
        20 RESEARCH             6500   12189466
        30 SALES                6501   12189466
        40 OPERATIONS           6501   12189466

SQL> update dept1 set dname=lower(dname) where deptno=10;

1 row updated.

SQL> commit;

Commit complete.

SQL>  select deptno,dname,
  2   dbms_rowid.rowid_block_number(rowid) blockno,
  3   ora_rowscn
  4   from dept1;

    DEPTNO DNAME             BLOCKNO ORA_ROWSCN
---------- -------------- ---------- ----------
        10 accounting           6500   12189534
        20 RESEARCH             6500   12189466
        30 SALES                6501   12189466
        40 OPERATIONS           6501   12189466
函数:SCN_TO_TIMESTAMP

SQL> select scn_to_timestamp(ora_rowscn) ts from dept1;

TS
---------------------------------------------------------------
10-SEP-08 03.25.50.000000000 PM
10-SEP-08 03.23.59.000000000 PM
10-SEP-08 03.23.59.000000000 PM
10-SEP-08 03.23.59.000000000 PM

3.阻塞
数据库中有5条常见的DML语句可能会阻塞:
insert,update,delete,merge,select for update

对于insert型阻塞,可以利用一个触发器来防止长时间的等待,如下:
SQL> create table demo(x int primary key);

Table created.

触发器脚本:
create or replace trigger demo_bifer
before insert on demo
for each row
declare
  l_lock_id number;
  resource_busy exception;
  pragma exception_init(resource_busy,-54);
begin
  l_lock_id := dbms_utility.get_hash_value(to_char(:new.x),0,1024);
  if (dbms_lock.request(id=>l_lock_id,
                        lockmode=>dbms_lock.x_mode,
                        timeout=>0,
                        release_on_commit=>TRUE)<>0)
  then
    raise resource_busy;
  end if;
end;

4.死锁 deadlock ----该死的死锁
SQL> update a set b=b where id=1;
update a set b=b where id=1
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource

Oracle认为死锁很少见,而且由于如此少见,所以每次出现死锁时它都会在服务器上创建一个跟踪文件.
文件内容如下:
*** 2008-09-10 16:28:01.921
*** ACTION NAME:() 2008-09-10 16:28:01.906
*** MODULE NAME:(SQL*Plus) 2008-09-10 16:28:01.906
*** SERVICE NAME:(SYS$USERS) 2008-09-10 16:28:01.906
*** SESSION ID:(142.9385) 2008-09-10 16:28:01.906
DEADLOCK DETECTED
[Transaction Deadlock]
Current SQL statement for this session:
update a set b=b where id=1
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
            ...................................

导致死锁的原因:
(1)外键未加索引
(2)位图的争用

----------------查找外键未加索引的表--------------
select table_name,constraint_name,
cname1||nvl2(cname2,','||cname2,null)||
nvl2(cname3,','||cname3,null)||nvl2(cname4,','||cname4,null)||
nvl2(cname5,','||cname5,null)||nvl2(cname6,','||cname6,null)||
nvl2(cname7,','||cname7,null)||nvl2(cname8,','||cname8,null)
 columns
from (select b.table_name,
             b.constraint_name,
             max(decode(position,1,column_name,null)) cname1,
             max(decode(position,2,column_name,null)) cname2,
             max(decode(position,3,column_name,null)) cname3,
             max(decode(position,4,column_name,null)) cname4,
             max(decode(position,5,column_name,null)) cname5,
             max(decode(position,6,column_name,null)) cname6,
             max(decode(position,7,column_name,null)) cname7,
             max(decode(position,8,column_name,null)) cname8,
             count(*) col_cnt
       from (select substr(table_name,1,30) table_name,
                    substr(constraint_name,1,30) constraint_name,
                    substr(column_name,1,30) column_name,
                    position
             from user_cons_columns) a,
             user_constraints b
       where a.constraint_name=b.constraint_name
         and b.constraint_type='R'
       group by b.table_name,b.constraint_name
       ) cons
   where col_cnt>ALL
     (select count(*)
        from user_ind_columns i
        where i.table_name=cons.table_name
          and i.column_name in (cname1,cname2,cname3,cname4,cname5,
                cname6,cname7,cname8)
     and i.column_position<=cons.col_cnt
   group by i.index_name
)
group by table_name,constraint_name,cname1,cname2,cname3,cname4,cname5,cname6,cname7,cname8
/

TABLE_NAME                     CONSTRAINT_NAME COLUMNS
------------------------------ --------------- -----------------------------
TEACHER                        FK_LESSONNAME   LESSON_NAME
EMP                            EMP_FK_DEPT     DEPTNO
EMP                            EMP_FK_EMP      MGR
C                              SYS_C007744     X

锁类型
1.DML锁
2.DDL锁
3.内部锁和闩

SQL> update dept1 set deptno=deptno+10;

已更新7行。
查询 'TX'事务锁的语句
 select username,
 v$lock.sid,
 trunc(id1/power(2,16)) rbs,
 bitand(id1,to_number('ffff','xxxx'))+0 slot,
 id2 seq,
 lmode,
 request
 from v$lock,v$session
 where v$lock.type='TX'
 and v$lock.sid=v$session.sid
 and v$session.username=USER

USERNAME                              SID        RBS       SLOT        SEQ      LMODE    REQUEST
------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
FTTEST                                125          4          5       5394          6          0

通过自连接来查询
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
'is blocking',
(select username from v$session where sid=b.sid) blockee,
b.sid
from v$lock a,v$lock b
where a.block=1
and b.request>0
and a.id1=b.id1
and a.id2=b.id2

TM锁
SQL> create table t1(x int);

表已创建。

SQL> create table t2(x int);

表已创建。

SQL> insert into t1 values(1);

已创建 1 行。

SQL> insert into t2 values(1);

已创建 1 行。

SQL> select
  2  (select username from v$session
  3  where sid=v$lock.sid) username,
  4  sid,id1,id2,lmode,request,block,v$lock.type
  5  from v$lock
  6  where sid=(select sid from v$mystat where rownum=1)
  7  /

USERNAME                              SID        ID1        ID2      LMODE    REQUEST      BLOCK TY
------------------------------ ---------- ---------- ---------- ---------- ---------- ---------- --
FTTEST                                125      57698          0          3          0          0 TM
FTTEST                                125      57699          0          3          0          0 TM
FTTEST                                125     196652       7072          6          0          0 TX

TX锁是事务锁,如果开启一个事务则会创建一个TX锁,直到commit或rollback才会释放这个锁
而TM锁(DML锁)则会在一个事务中有多个,而且ID1会和object_id相同
select object_name,object_id from user_objects
where object_name in ('T1','T2');

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/67668/viewspace-448701/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2007-12-26

  • 博文量
    35
  • 访问量
    144468