12
返回列表 发新帖
楼主: wabjtam123

[精华] 同一看过程只能独立跑,不能重复一起执行的控制,大家有好建议没?

[复制链接]
论坛徽章:
50
2014年世界杯参赛球队: 荷兰
日期:2014-07-11 07:56:59蛋疼蛋
日期:2012-03-06 07:22:542012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-01-04 11:53:29蛋疼蛋
日期:2011-11-11 15:47:00ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
11#
 楼主| 发表于 2010-1-23 09:54 | 只看该作者
原帖由 newkid 于 2010-1-23 08:51 发表
你把两个USERENV('SESSIONID');分别输出来看是不是相同的?如果是同一个SESSION, 当然不会报错,锁是自己持有的,再加锁一次也不报错。

NEWKID兄,感谢回复!
我已经在两个SQLPLUS窗口下同时执行了。

第一个SQLPLUS窗口VAJS_149:
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

vajs_149@RQRQ> exec pkg_mgacct.P_MAIN(V_RULE_REC_SEQ => 372,V_CYCLE_ID => 200909);

PL/SQL 过程已成功完成。

vajs_149@RQRQ> select * from v$mystat where rownum=1;

       SID STATISTIC#      VALUE
---------- ---------- ----------
       149          0          1


另一SQLPLUS窗口是VAJS_140
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options


vajs_140@RQRQ>  exec pkg_mgacct.P_MAIN(V_RULE_REC_SEQ => 372,V_CYCLE_ID => 200909);

PL/SQL 过程已成功完成。

vajs_149@RQRQ> select * from v$mystat where rownum=1;

       SID STATISTIC#      VALUE
---------- ---------- ----------
       140         0          1


都能成功!(确认是同时执行的,就是第一个窗口执行没结束的时候第二个窗口继续执行这个业务的意思,我想期待这个第二个窗口报错退出,但是却没能成功,两个窗口同时执行,最终都能成功结束,晕,呵呵)


USERENV('SESSIONID');这两个我在调试的时候实验过了,一个是33461,另一个是33462
值不一样,这个在PLSQL DEVELOPE测试过了。

呵呵,真是有点想不明白啊


对了,NEWKID兄,你能否能把我的这个P_BASE的注册和退出注册模块引用到你随便的任一个过程中,然后把这个引用了P_BASE的过程测试一把,同时跑两次,你能成功吗?能避免同时跑吗?

再次感谢NEWKID兄!

[ 本帖最后由 wabjtam123 于 2010-1-23 10:05 编辑 ]

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
12#
发表于 2010-1-23 12:05 | 只看该作者
怎么又冒出个pkg_mgacct.P_MAIN?你先从最底层的互斥功能测起,像我这样:

SQL> EXEC pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test');
BEGIN pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test'); END;

*
ERROR at line 1:
ORA-20004: 当前进程已在处理中。。。。。
ORA-06512: at "JSU.PKG_BASE", line 86
ORA-06512: at line 1

使用道具 举报

回复
论坛徽章:
50
2014年世界杯参赛球队: 荷兰
日期:2014-07-11 07:56:59蛋疼蛋
日期:2012-03-06 07:22:542012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-01-04 11:53:29蛋疼蛋
日期:2011-11-11 15:47:00ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
13#
 楼主| 发表于 2010-1-23 12:14 | 只看该作者
原帖由 newkid 于 2010-1-23 12:05 发表
怎么又冒出个pkg_mgacct.P_MAIN?你先从最底层的互斥功能测起,像我这样:

SQL> EXEC pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test');
BEGIN pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test'); END;

*
ERROR at line 1:
ORA-20004: 当前进程已在处理中。。。。。
ORA-06512: at "JSU.PKG_BASE", line 86
ORA-06512: at line 1

呵呵,NEWKID兄,这个之前我实验过了,这个是没问题的,其实表示底层的写法是没问题,只是在你某个过程想应用到我这个注册包的时候,出问题了
SQL> EXEC pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test');

begin pkg_base.P_REGISTER(1401,'pkg_mgacct',416,'test'); end;

ORA-20004: 当前进程已在处理中。。。。。
ORA-06512: 在 "VAJS.PKG_BASE", line 126
ORA-06512: 在 line 1


但是我是要在PKG_MGACCT中调用它,这个的P_MAIN函数是这样写的,从执行这个来引用就不成功了。

Procedure P_main(V_RULE_REC_SEQ IN NUMBER DEFAULT NULL, V_CYCLE_ID IN NUMBER DEFAULT NULL,v_point_type IN VARCHAR2 DEFAULT null) as

/*
  
  说明:
  
  主程序
  
  1、p_mgacct主程序调用P_JUDGE_BRAK_POINT 来做配置表判断及自动校验
  
  2、p_mgacct主程序根据入参类型v_point_type的取值来调用p_do程序
  
  其中:   p_do程序调用P_GENMERGESQL过程,从P_GENMERGESQL中获取生产的MERGE的SQL文本
           p_do程序根据一定的业务逻辑获取断点(三种类型)
           接着p_do程序利用断点和SQL文本,拼成正确的SQL语句,并EXECUTE IMMEDATE 执行
  
*/


Begin

     /*
  以下模块调用的目的是能够保证p_main可以不带参数,从tpva_mgacct_rule从提取
  rec_seq,即调用所有业务。也可以根据输入参数决定
  */
   
  

   IF V_RULE_REC_SEQ IS NULL THEN
   

      FOR J IN (SELECT * FROM TPVA_MGACCT_RULE WHERE STATE='00A' AND point_class='5PC' AND module_id=1401 ORDER BY rec_seq) LOOP
   
   
   
   /* 这里写进point_class='5PC'主要是为了保证当前特殊业务一定要能支持!就是说,当要不输入
    参数,默认全部执行的时候,只能执行生产线业务!*/
   
      
       p_judge_break_point(J.REC_SEQ);  
       pkg_base.P_REGISTER(1401,'pkg_mgacct',J.REC_SEQ,null);   
         FOR I IN (SELECT * FROM BREAK_POINT_MGACCT
                WHERE point_id=J.REC_SEQ  ----这里非常重要!如果写v_rule_rec_seq就不对了,变成NULL了
                AND ( point_Type=v_point_Type OR v_point_Type IS NULL)
                ORDER BY point_type,module_id,billing_line_id)  --排序的目的是为了明确程序出错后,可判断已经执行到哪里     
         LOOP      
           p_do( V_RULE_REC_SEQ =>J.REC_SEQ, V_CYCLE_ID=>V_CYCLE_ID,v_billing_line_id=>i.billing_line_id,v_point_type =>i.point_type);
           
         END LOOP;
         pkg_base.P_UNREGISTER(1401,'pkg_mgacct',J.REC_SEQ);
      END LOOP;
     
    ELSE
      p_judge_break_point(V_RULE_REC_SEQ);
      pkg_base.P_REGISTER(1401,'pkg_mgacct',V_RULE_REC_SEQ,NULL);
      FOR I IN (SELECT * FROM BREAK_POINT_MGACCT
                WHERE point_id=V_RULE_REC_SEQ ----这里写 V_RULE_REC_SEQ没错,因为值不为空了
                AND  ( point_Type=v_point_Type OR v_point_Type IS NULL)
                ORDER BY point_id,module_id,billing_line_id) --排序的目的是为了明确程序出错后,可判断已经执行到哪里         
      LOOP
      
      p_do( V_RULE_REC_SEQ =>V_RULE_REC_SEQ, V_CYCLE_ID=>V_CYCLE_ID,v_billing_line_id=>i.billing_line_id,v_point_type =>i.point_type);
      
   
      END LOOP;
      --dbms_lock.sleep(2000);
      pkg_base.P_UNREGISTER(1401,'pkg_mgacct',V_RULE_REC_SEQ);
    END IF;
  
         
  END P_MAIN;
  
  
  
end pkg_MgAcct;

[ 本帖最后由 wabjtam123 于 2010-1-23 12:22 编辑 ]

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
14#
发表于 2010-1-23 21:59 | 只看该作者
检查一下你的p_do里面有没有提交,或者p_do调用的下层有没有提交。如果里面有DDL(因为我看到你提到动态SQL,不知道有没有创建临时表或视图的情况)也会提交。
如果你过早提交,锁就释放了。
如果你过程运行很快,测试时也会看不到锁。

使用道具 举报

回复
论坛徽章:
50
2014年世界杯参赛球队: 荷兰
日期:2014-07-11 07:56:59蛋疼蛋
日期:2012-03-06 07:22:542012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-01-04 11:53:29蛋疼蛋
日期:2011-11-11 15:47:00ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
15#
 楼主| 发表于 2010-1-25 09:44 | 只看该作者
原帖由 newkid 于 2010-1-23 21:59 发表
检查一下你的p_do里面有没有提交,或者p_do调用的下层有没有提交。如果里面有DDL(因为我看到你提到动态SQL,不知道有没有创建临时表或视图的情况)也会提交。
如果你过早提交,锁就释放了。
如果你过程运行很快,测试时也会看不到锁。

NEWKID兄,非常感谢!
周末去乡下没上网,今天一来看到你的回帖,果然发现问题所在了,确实是P_DO中有提交动作,我其实之前考虑过这个问题了,把所有的P_DO中的COMMIT都去掉了,今天再查一下,发现其中有漏网之鱼,P_DO有引用过程 ,该过程里有COMMIT,去掉就都解决了。呵呵。
不过我隐隐约约觉得还有一个小问题,就是我如果把程序强行中断后,tg_module 中的记录已存在的情况下(由于强行中断,所以走不了P_UNREGISTER中的P_MOVE,记录不会从TG_MODULE转移到TG_MODULE_HISTORY中),就无法控制不重复跑了。两个窗口同时执行居然不报错。
这个问题我再看看,按理说这个代码和是否已存在记录无关啊,有存在记录就是不插了,但是先获得的人还是会得到UPDATE NO WAIT啊。我的P_MOVE其实主要是为了COMMIT,移除动作只是为了不要有太多垃圾在里面啊。
NEWKID兄真是强大,这个方法比我之前的COUNT(*)来的严谨多了,我的COUNT(*)根本就是运气,存在一致读的陷阱,不科学!

[ 本帖最后由 wabjtam123 于 2010-1-25 09:52 编辑 ]

使用道具 举报

回复
论坛徽章:
50
2014年世界杯参赛球队: 荷兰
日期:2014-07-11 07:56:59蛋疼蛋
日期:2012-03-06 07:22:542012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-02-13 15:09:522012新春纪念徽章
日期:2012-01-04 11:53:29蛋疼蛋
日期:2011-11-11 15:47:00ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
16#
 楼主| 发表于 2010-1-25 11:22 | 只看该作者
奇怪,我测试把
p_judge_break_point(J.REC_SEQ);  
pkg_base.P_REGISTER(1401,'pkg_mgacct',J.REC_SEQ,null);   
的位置对调一下,变成
pkg_base.P_REGISTER(1401,'pkg_mgacct',J.REC_SEQ,null);   
p_judge_break_point(J.REC_SEQ);  
后,发现tg_module中有记录,也可以控制不重复运行了。(p_judge_break_point有一个对表update 的动作,不提交)
所以我觉得应该放在后面执行,但是奇怪的是,我又改顺序,却都可以了。
有点怪怪的。
不过感觉问题是基本解决了,这个p_judge_break_point(J.REC_SEQ); 从理论上来说当然要放在后面,即便放在前面,也应该COMMIT掉才合理。

呵呵,这个方法应该还是很有实用范围的,非常感谢NEWKID兄,我之前的方法测试的时候出不了问题,但是一旦出现频繁使用的一致读问题出现,没法控制并发,死都不知道怎么死

使用道具 举报

回复
论坛徽章:
0
17#
发表于 2010-5-24 18:46 | 只看该作者
贴段使用dbms_lock来保证这一点的代码,希望对新人们有所帮助:

create table zsj_procedure_xmode(ins_time date default sysdate,seconds number);


create or replace procedure procedure_xmode(v_seconds number)
is
   v_lockhandle       varchar2(128);
   v_lock_status      pls_integer;
   v_release_status   pls_integer;
begin
   dbms_lock.allocate_unique(lockname =>'procedure_xmode,'||v_seconds,lockhandle =>v_lockhandle);
   v_lock_status:=dbms_lock.request(lockhandle=>v_lockhandle,lockmode => Dbms_Lock.x_mode,timeout => 0,release_on_commit => false);
   if(v_lock_status=1) then
       raise_application_error(-20001,'相同输入参数的该过程正在运行中,请稍候再试!');
   end if;
   for i in 1..v_seconds
   loop
       insert into zsj_procedure_xmode(ins_time,seconds) values(sysdate,v_seconds);
       dbms_lock.sleep(1);
   end loop;
   commit;
   if(v_lock_status=0) then
      v_release_status:=dbms_lock.release(lockhandle => v_lockhandle);
   end if;
end;
/

使用道具 举报

回复
论坛徽章:
32
奥运会纪念徽章:摔跤
日期:2012-08-23 11:03:05青年奥林匹克运动会-击剑
日期:2014-09-19 10:58:152014年世界杯参赛球队:巴西
日期:2014-07-07 12:19:232014年世界杯参赛球队: 瑞士
日期:2014-05-19 12:18:36马上有钱
日期:2014-04-08 12:12:232014年新春福章
日期:2014-04-04 14:20:47马上有钱
日期:2014-02-18 16:43:092014年新春福章
日期:2014-02-18 16:43:09红旗
日期:2014-02-14 15:15:55优秀写手
日期:2013-12-18 09:29:16
18#
发表于 2010-5-26 15:10 | 只看该作者
收藏了慢慢看。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表