【永恒的瞬间】
☜Give me hapy ☞

在Php格式中,冒号被转义了,应该在的有的old和new前加冒号,以示更加清晰.

--oracle悲观封锁应用示例(以下包是研究Oracle的11i后模拟的):
--ttx_tmp.sql

代码:

create
or replace package ttx_temp_pkg is
  g_ok varchar2
(2) := 'OK';    
  
g_changed varchar2(21) :='CHANGED BY OTHER USER';
  
g_no_row varchar2(14) := 'NO ROW UPDATED';
  
  
procedure lock_row
  
(
    
x_message         out nocopy varchar2,
    
p_id              in number,
    
p_owner           in varchar2,
    
p_object_name     in varchar2,
    
p_subobject_name  in varchar2,
    
p_object_id       in number,
    
p_data_object_id  in number,
    
p_object_type     in varchar2,
    
p_created         in date,
    
p_last_ddl_time   in date,
    
p_timestamp       in varchar2,
    
p_status          in varchar2,
    
p_temporary       in varchar2,
    
p_generated       in varchar2,
    
p_secondary       in varchar2
  
);
  
  
procedure update_row
  
(
    
x_message         out nocopy varchar2,
    
p_id              in number,
    
p_owner           in varchar2,
    
p_object_name     in varchar2,
    
p_subobject_name  in varchar2,
    
p_object_id       in number,
    
p_data_object_id  in number,
    
p_object_type     in varchar2,
    
p_created         in date,
    
p_last_ddl_time   in date,
    
p_timestamp       in varchar2,
    
p_status          in varchar2,
    
p_temporary       in varchar2,
    
p_generated       in varchar2,
    
p_secondary       in varchar2  
  
);
  
  
procedure delete_row
  
(
    
p_id in number,
    
x_message out nocopy varchar2
  
);

end ttx_temp_pkg;
/

create or replace package body ttx_temp_pkg is

  procedure lock_row
  
(
    
x_message         out nocopy varchar2,
    
p_id              in number,
    
p_owner           in varchar2,
    
p_object_name     in varchar2,
    
p_subobject_name  in varchar2,
    
p_object_id       in number,
    
p_data_object_id  in number,
    
p_object_type     in varchar2,
    
p_created         in date,
    
p_last_ddl_time   in date,
    
p_timestamp       in varchar2,
    
p_status          in varchar2,
    
p_temporary       in varchar2,
    
p_generated       in varchar2,
    
p_secondary       in varchar2
  
) is
    cursor cur_ttx_temp is
      select
        id
,
        
owner,
        
object_name,
        
subobject_name,
        
object_id,
        
data_object_id,
        
object_type,
        
created,
        
last_ddl_time,
        
timestamp,
        
status,
        
temporary,
        
generated,
        
secondary
      from ttx_temp
      where id
= p_id
      
for update nowait;
    
ctt cur_ttx_temp%rowtype;  
            
  
begin
      open cur_ttx_temp
;
      
fetch cur_ttx_temp into ctt;      
      if ((
ctt.owner=p_owner) or
          (
ctt.owner is null and p_owner is null))
        and ((
ctt.object_name=p_object_name) or
          (
ctt.object_name is null and p_object_name is null))
        and ((
ctt.subobject_name=p_subobject_name) or
          (
ctt.subobject_name is null and p_subobject_name is null))
        and ((
ctt.object_id=p_object_id) or
          (
ctt.object_id is null and p_object_id is null))
        and ((
ctt.data_object_id=p_data_object_id) or
          (
ctt.data_object_id is null  and p_data_object_id is null))
        and ((
ctt.object_type=p_object_type) or
          (
ctt.object_type is null and p_object_type is null))
        and ((
ctt.created=p_created) or
          (
ctt.created is null and p_created is null))
        and ((
ctt.last_ddl_time=p_last_ddl_time) or
          (
ctt.last_ddl_time is null and p_last_ddl_time is null))
        and ((
ctt.timestamp=p_timestamp) or
          (
ctt.timestamp is null and p_timestamp is null))
        and ((
ctt.status=p_status) or
          (
ctt.status is null and p_status is null))
        and ((
ctt.temporary=p_temporary) or
          (
ctt.temporary is null and p_temporary is null))
        and ((
ctt.generated=p_generated) or
          (
ctt.generated is null and p_generated is null))
        and ((
ctt.secondary=p_secondary) or
          (
ctt.secondary is null and p_secondary is null)) then        
        x_message
:= g_ok;    
      else
        
x_message := g_changed;
      
end if;  
      
close cur_ttx_temp;
     
  
exception
    when others then
      x_message
:= substrb(sqlcode||'/'||sqlerrm,1,200);  
      if
cur_ttx_temp%isopen then
        close cur_ttx_temp
;
      
end if;
  
end;
  
  
procedure update_row
  
(
    
x_message         out nocopy varchar2,
    
p_id              in number,
    
p_owner           in varchar2,
    
p_object_name     in varchar2,
    
p_subobject_name  in varchar2,
    
p_object_id       in number,
    
p_data_object_id  in number,
    
p_object_type     in varchar2,
    
p_created         in date,
    
p_last_ddl_time   in date,
    
p_timestamp       in varchar2,
    
p_status          in varchar2,
    
p_temporary       in varchar2,
    
p_generated       in varchar2,
    
p_secondary       in varchar2  
  
) is
  begin
      update ttx_temp
      set    
      owner          
= p_owner,           
      
object_name    = p_object_name,
      
subobject_name = p_subobject_name,
      
object_id      = p_object_id,
      
data_object_id = p_data_object_id,
      
object_type    = p_object_type,
      
created        = p_created,
      
last_ddl_time  = p_last_ddl_time,
      
timestamp      = p_timestamp,
      
status         = p_status,
      
temporary      = p_temporary,
      
generated      = p_generated,
      
secondary      = p_secondary       
      where id
=p_id;
      
      if
sql%rowcount > 0 then
        x_message
:= g_ok;
      else
        
x_message := g_no_row;
    
end if;  
  
exception
    when others then
      x_message
:= substrb(sqlcode||'/'||sqlerrm,1,200);
  
end;
  
  
procedure delete_row
  
(
    
p_id in number,
    
x_message out nocopy varchar2
  
) is
  begin
      delete ttx_temp
      where id
=p_id;
      if
sql%rowcount > 0 then
        x_message
:= g_ok;
      else
        
raise no_data_found;
      
end if;
  
  
exception
    when others then
        x_message
:= substrb(sqlcode||'/'||sqlerrm,1,200);    
  
end;  

end ttx_temp_pkg;
/



--环境准备


ttx@TTX>create table ttx_temp as select *
2 from dba_objects where rownum < 100;

Table created.

ttx@TTX>alter table ttx_temp add id number;

Table altered.

ttx@TTX>create sequence ttx_temp_s;

Sequence created.

ttx@TTX>update ttx_temp set id = ttx_temp_s.nextval;

99 rows updated.

ttx@TTX>commit;

Commit complete.

ttx@TTX>alter table ttx_temp modify id not null;

Table altered.


ttx@TTX>alter table ttx_temp add constraint ttx_temp_pk primary key(id);

Table altered.

ttx@TTX>show errros;
SP2-0158: unknown SHOW option "errros"
ttx@TTX>desc ttx_temp
Name Null? Type
----------------------------------------------------- -------- ------------------------------------
OWNER VARCHAR2(30)
OBJECT_NAME VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(19)
CREATED DATE
LAST_DDL_TIME DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
ID NOT NULL NUMBER

ttx@TTX>column object_name format a30
ttx@TTX>column owner format a15
ttx@TTX>select owner,object_name from ttx_temp where id < 10;

OWNER OBJECT_NAME
--------------- ------------------------------
SYS ICOL$
SYS I_USER1
SYS CON$
SYS UNDO$
SYS C_COBJ#
SYS I_OBJ#
SYS PROXY_ROLE_DATA$
SYS I_IND1
SYS I_CDEF2

9 rows selected.

ttx@TTX>desc ttx_temp_pkg
PROCEDURE DELETE_ROW
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
P_ID NUMBER IN
X_MESSAGE VARCHAR2 OUT
PROCEDURE LOCK_ROW
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
X_MESSAGE VARCHAR2 OUT
P_ID NUMBER IN
P_OWNER VARCHAR2 IN
P_OBJECT_NAME VARCHAR2 IN
P_SUBOBJECT_NAME VARCHAR2 IN
P_OBJECT_ID NUMBER IN
P_DATA_OBJECT_ID NUMBER IN
P_OBJECT_TYPE VARCHAR2 IN
P_CREATED DATE IN
P_LAST_DDL_TIME DATE IN
P_TIMESTAMP VARCHAR2 IN
P_STATUS VARCHAR2 IN
P_TEMPORARY VARCHAR2 IN
P_GENERATED VARCHAR2 IN
P_SECONDARY VARCHAR2 IN
PROCEDURE UPDATE_ROW
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
X_MESSAGE VARCHAR2 OUT
P_ID NUMBER IN
P_OWNER VARCHAR2 IN
P_OBJECT_NAME VARCHAR2 IN
P_SUBOBJECT_NAME VARCHAR2 IN
P_OBJECT_ID NUMBER IN
P_DATA_OBJECT_ID NUMBER IN
P_OBJECT_TYPE VARCHAR2 IN
P_CREATED DATE IN
P_LAST_DDL_TIME DATE IN
P_TIMESTAMP VARCHAR2 IN
P_STATUS VARCHAR2 IN
P_TEMPORARY VARCHAR2 IN
P_GENERATED VARCHAR2 IN
P_SECONDARY VARCHAR2 IN

ttx@TTX>




--前台操作用户通过前台界面查出需要的数据(select * from ttx_temp),
--然后对对ID=1的这行数据的SUBOBJECT_NAME进行修改后提交更新时,
--程序应该类似于下面的方式调用,就可以保证数据更新不被丢失


代码:

begin
  
--old.xxx 在调用时用具体的初始值替代,在Oracle Form和Delphi中都支持Old和New的模式,
  --
在JAVA中我不太清楚,应该是有办法的
  ttx_temp_pkg
.lock_row
  
(
    
x_message         => v_message,       
    
p_id              => id,            
    
p_owner           => old.owner,
    
p_object_name     => old.object_name,
    
p_subobject_name  => old.subobject_name,
    
p_object_id       => old.object_id,
    
p_data_object_id  => old.data_object_id,
    
p_object_type     => old.object_type,
    
p_created         => old.created,
    
p_last_ddl_time   => old.last_ddl_time,
    
p_timestamp       => old.timestamp,
    
p_status          => old.status,
    
p_temporary       => old.temporary,
    
p_generated       => old.generated,
    
p_secondary       => old.secondary
  
);
  
  if
v_message = 'OK' then
    ttx_temp_pkg
.update_row      
    
(
      
x_message         => v_message,
      
p_id              => id,--用具体的值代替
      p_owner           
=> new.owner,         
      
p_object_name     => new.object_name,   
      
p_subobject_name  => new.subobject_name,
      
p_object_id       => new.object_id,     
      
p_data_object_id  => new.data_object_id,
      
p_object_type     => new.object_type,   
      
p_created         => new.created,       
      
p_last_ddl_time   => new.last_ddl_time,
      
p_timestamp       => new.timestamp,     
      
p_status          => new.status,        
      
p_temporary       => new.temporary,     
      
p_generated       => new.generated,     
      
p_secondary       => new.secondary      
    
);
    
    if
v_message = 'OK' then
      
--数据更新成功
    
else
      --
数据更新失败  
    end
if;
    
  else
    --
锁定行出错,具体信息为:v_message  
  end
if;  
  
end;




--Oracle乐观封锁示例:
--前台操作用户通过前台界面查出需要的数据(select t.rowid,t.* from ttx_temp t),
--然后对对ID=1的这行数据的SUBOBJECT_NAME进行修改提交更新,
--应该使用的程序代码类似为(Delphi可以自已产生,其余的不太清楚):



代码:

update ttx_temp t
set t
.subobject_name=new.subobject_name
where t
.rowid=_rowid--用具体的值代替
and t.id=old.id
and nvl(t.owner,'"$!')=nvl(old.owner,'"$!')
and
nvl(t.object_name,'"$!')=nvl(old.object_name,'"$!')
and
nvl(t.object_id,'"$!')=nvl(old.object_id,'"$!')
and
nvl(t.data_object_id,'"$!')=nvl(old.data_object_id,'"$!')
and
nvl(t.object_type,'"$!')=nvl(old.object_type,'"$!')
and
nvl(t.created,'"$!')=nvl(old.created,'"$!')
and
nvl(t.last_ddl_time,'"$!')=nvl(old.last_ddl_time,'"$!')
and
nvl(t.timestamp,'"$!')=nvl(old.timestamp,'"$!')
and
nvl(t.status,'"$!')=nvl(old.status,'"$!')
and
nvl(t.temporary,'"$!')=nvl(old.temporary,'"$!')
and
nvl(t.generated,'"$!')=nvl(old.generated,'"$!')
and
nvl(t.secondary,'"$!')=nvl(old.secondary,'"$!');



--乐观封锁的代码量相对来说少很多,但增大了丢失更新的风险。在实际应用中
--到底是使用悲观封锁还是乐观封锁,由开发人员来定。不过Oracle 11i版的ERP
--如此庞大复杂的系统都使用悲观封锁,没有理由说明乐观封锁优于悲观封锁。
posted on 2007-04-25 20:42 ☜♥☞MengChuChen 阅读(539) 评论(0)  编辑  收藏 所属分类: ORACLE

只有注册用户登录后才能发表评论。


网站导航: