您的位置:首页 > 其它

EBS Form开发中复写on-lock触发器

2014-12-25 11:04 288 查看
一般情况下二次开发form中(不论是基于表还是基于视图的数据块),不需要复写ON-LOCK触发器,系统会自动处理的很好,那么,出于对form开发更为深入的探索,我决定还是仔细研究研究这个触发器的功用,触发时间,以有相应的pl/sql处理过程等。以此可以作为研究其它触发器的一个范例,找到一个学习研究的方法。

form端的ON-LOCK触发器用于获取oracle数据表的行级排他锁,当ON-LOCK 触发器fire时,他会试图去获得这个锁,如果这时没有其它session获得这个锁,或者说其它session己经释放这个锁,那么我们的form会很顺利的获得。否则会抛出 app_exceptions.record_lock_exception异常。一般我们会写一个loop ..end loop;块出来,再定义一个计数器counter计录循环次数,把它作为参数传入到app_exception.record_lock_error(counter);处理过程中。这时,当这个counter为2,4,6,8这样的偶数时,在form中会弹出message,用于用户选择是否继续试图获得lock,或中止procedure的执行。因为在app_exception.record_lock_error()过程的最后,会raise一个form_trigger_failure的异常。

哪么on-lock触发器在什么时候触发呢,帮助中说:“Fires whenever Form Builder would normally attempt to lock a row, such as when an operator presses a key to modify data in an item. The trigger fires between the keypress and the display of the modified data. ”

就在当我们进入到form,查询到记录之后,然后,当我们在某一个item中输入内容与这个内容display到显示屏之间那不知多么短的时间内,it fires!

现在我们来看看比较完整的处理代码,为了简便期间,我对代码进行了简化:

procedure lock_row as

counter NUMBER;

cursor C is

select

l_id,

out_date,

back_date,

customer,

from cdm_loan

where rowid = :loan.row_id

for update of l_id nowait;

---for update of <table.columons>, <table.columons> nowait;这里"of"只在多表链接查询时才有用,意为锁定指定 列所对应的表,会根据where条件来获得该表的某一行的锁 ,nowait 表示如果获取不了锁,那么直接返 回错误.

recinfo C%rowtype;

begin

fnd_message.debug('lock_row is begin');

counter := 0; --循环记数器(变量)

loop

begin

counter := counter+1;

open C;

fetch C into recinfo;

if (C%NOTFOUND) then

close C;

fnd_message.set_name('FND','FORM_RECORD_DELETED');

fnd_message.error;

raise form_trigger_failure;

end if;

close C;

if (

-- 检查固定列,数据库中一般为非空字段,form中对应的item的require属性一般为yes,同时,block的query data source columns中相应列的mandatory属性要勾上

(recinfo.l_id = :loan.l_id)

AND (recinfo.status = :loan.s_id)

-- 检查非固定列,数据库中一般指为充许空字段,form中对应的item的require属性一般为no,block的query data source columns中相应列的mandatory属性要去掉勾

AND ((recinfo.out_date = :loan.out_date)

OR ((recinfo.out_date is null)

AND (:loan.out_date is null)))

AND ((recinfo.back_date = :loan.back_date)

OR ((recinfo.back_date is null)

AND (:loan.back_date is null)))

AND ((recinfo.customer = :loan.customer)

OR ((recinfo.customer is null)

AND (:loan.customer is null)))

)

then

return;---满足条件后退出循环

else--当form中的值同数据库中的值不匹配时的处理

fnd_message.set_name('FND', 'FORM_RECORD_CHANGED');

fnd_message.error;

raise form_trigger_failure;

end if;

exception ---当不能获取锁时,的异常代码,该异常由系统自动抛出

when app_exceptions.record_lock_exception then

app_exception.record_lock_error(counter);

end;

end loop;

end lock_row;

这里要明白几点:

1、我们调用此ON-LOCK触发器代码时,相应表中的某行即被锁定,众所周知,oracle数据库执行for update时,即获得锁,如果不commit或rollback或断掉session,这个锁是不会被主动释放的。但是在form中,我们只要保存这条记录时,或关掉form窗口,就会释放锁,不论你是否在ON-UPDATE中真正的执行了update语句,系统都会通过自动给你执行一个commit来实现。

2、loop ..end loop中的begin ..end有什么用? 这个begin..end是无奈之举,因为如果没有begin ..end 的话,我们就不能在procedure中的一个特定的范围内处理异常(exceptions语句),这样的结果会出现一旦loop中某一个记录出了问题,那么整个procedure都会中止,当遇到海量数据的处理时,非常不便。因为没有异常处理代码的异常会被传入上一级。

3,程序要保证在获取锁的时刻form界面上的值要和数据库中值相匹配,才行。如果有不匹配的情况就会强制让你重新查询,再来修改,在修改保存前,你都拥这个锁。

当第一次进入form时,查询后,在某一个item上输入内容,触发on-lock,这时,眼睛看着界面上item的内容明明改变,但是却成功通过了on-lock中数据一致性的验证,这是为什么呢,因为界面上的内容还没有被保存到相应item的实际value中,要通过保存记录,才会更新界面内容。要明白这一点,可以通过不在on-update中写更新代码来搞清楚。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: