首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DBMS调度程序

DBMS调度程序
EN

Stack Overflow用户
提问于 2020-01-04 15:23:42
回答 1查看 86关注 0票数 0

我有两个过程p1和p2,前者打印1到10,后者打印10到1,我使用调度程序并行运行这两个过程。我的代码是

代码语言:javascript
复制
BEGIN
dbms_scheduler.create_job (
job_name           =>  'j1a',
job_type           =>  'STORED_PROCEDURE',
job_action         =>  'p1',
start_date        =>  SYSTIMESTAMP,
repeat_interval    =>  'FREQ=DAILY', /* every  day */
enabled         => TRUE
);
DBMS_SCHEDULER.CREATE_JOB (
job_name           =>  'j2a',
job_type           =>  'STORED_PROCEDURE',
job_action         =>  'p2',
start_date        =>  SYSTIMESTAMP,
repeat_interval    =>  'FREQ=DAILY' ,/* every other day */
enabled             => TRUE
);
end;
BEGIN
DBMS_SCHEDULER.RUN_JOB(
JOB_NAME            => 'j1a,j2a'
--USE_CURRENT_SESSION => FALSE
);
end;

我得到的输出结果是

代码语言:javascript
复制
1
2
3
4
5
6
7
8
9
10
10
9
8
7

但不是像

代码语言:javascript
复制
1
2
10
9
8
3
..

请在这方面帮助我。

EN

回答 1

Stack Overflow用户

发布于 2020-01-04 23:48:02

您运行的作业如下所示:

代码语言:javascript
复制
DBMS_SCHEDULER.RUN_JOB(
JOB_NAME            => 'j1a,j2a'
--USE_CURRENT_SESSION => FALSE
);

USE_CURRENT_SESSION的默认值为true。这意味着这两个作业在同一会话中运行,这意味着它们以串行方式以方式运行。没有办法改变这种行为:一个会话一次只能运行一个作业。

您可以通过取消注释USE_CURRENT_SESSION参数设置来并行运行这些作业,但是这样您就不会在会话中看到输出。但是,有一个选项:使用DBMS_PIPE。DBMS_PIPE是一个Oracle内置库,它允许会话相互通信。在这种情况下,您可以使用它将消息从后台作业发送到另一个会话,该会话将接收消息并将其写入DBMS_OUTPUT缓冲区。

下面的代码可能看起来有点过分满足您的需求,但自从我上次使用DBMS_PIPE以来已经有十多年了,生锈的管道对健康有害,所以我们开始吧!

这是一个玩具信息管装。它有两个过程-一个用于发送消息,另一个用于读取消息:

代码语言:javascript
复制
create or replace package messaging is

subtype t_message is varchar2(128);

c_pipe_name constant varchar2(30) := 'MSG_PIPE';
c_stop      constant t_message    := 'STOP';

procedure listen (p_timeout in number default null);

procedure send (p_message in t_message);

end messaging;
/

简单地说,监听过程保持打开,直到任何发送者通知它停止为止。下面是包的实现:

代码语言:javascript
复制
create or replace package body messaging is

procedure listen (p_timeout in number default null) is

  l_timeout pls_integer;
  l_message t_message := 'waiting';
  l_status  pls_integer;

begin

  dbms_output.put_line(c_pipe_name || ' listening');

  l_status := DBMS_PIPE.create_pipe(pipename  => c_pipe_name
                                    , private => false);

  l_timeout := coalesce(p_timeout, DBMS_PIPE.maxwait);

  while l_message != c_stop loop

    l_status  := DBMS_PIPE.receive_message(pipename  => c_pipe_name
                                           , timeout => l_timeout);

    if l_status = 0 then

       DBMS_PIPE.unpack_message(l_message);
       dbms_output.put_line('Message received: ' || l_message);

    end if;

  end loop;

  l_status := DBMS_PIPE.remove_pipe(pipename => c_pipe_name);

  dbms_output.put_line(c_pipe_name || ' stopped');

end listen;

procedure send (p_message in t_message) is

  l_status    number;

begin

  DBMS_PIPE.pack_message(p_message);
  l_status := DBMS_PIPE.send_message(c_pipe_name);

end send;

end messaging;
/

我已经重写了您的存储过程来调用messaging.send()

代码语言:javascript
复制
create or replace procedure p1 is
  l_message   varchar2(80) := 'P#1:';
begin

  for idx in 1..10 loop
      messaging.send(l_message || to_char(idx));      
      dbms_session.sleep(1);
  end loop;

  messaging.send(messaging.c_stop);

end;
/
create or replace procedure p2 is
  l_message   varchar2(80) := 'P#2:';
begin

  for idx in reverse 1..10 loop
      messaging.send(l_message || to_char(idx));      
      dbms_session.sleep(1);  
  end loop;

  messaging.send(messaging.c_stop);

end;
/

这些例程使用sleep(),因为我手动运行它们进行测试,并且必须确保第一个例程在我启动第二个例程之前没有完成:当它们作为作业运行时,您可能不需要它们。(顺便说一句,我使用了期待已久的Robertson增强DBMS_SESSION.SLEEP(),因为我运行的是Oracle18c;如果您使用的是较早的版本,则可能需要要求数据库管理员授予您在DBMS_LOCK上执行或不休眠执行的权限。)

为了确保您的作业提交代码的完整性:

代码语言:javascript
复制
BEGIN
  dbms_scheduler.create_job (
    job_name           =>  'j1a',
    job_type           =>  'STORED_PROCEDURE',
    job_action         =>  'p1',
    start_date        =>  SYSTIMESTAMP,
    repeat_interval    =>  'FREQ=DAILY', /* every  day */
    enabled         => TRUE
  );
  DBMS_SCHEDULER.CREATE_JOB (
    job_name           =>  'j2a',
    job_type           =>  'STORED_PROCEDURE',
    job_action         =>  'p2',
    start_date        =>  SYSTIMESTAMP,
    repeat_interval    =>  'FREQ=DAILY' ,/* every other day */
    enabled             => TRUE
  );
end;
/

现在,我设置了一个会话来监听消息...

代码语言:javascript
复制
begin
  messaging.listen();
end;
/

..。在另一个会话中,我启动您的作业在后台运行:

代码语言:javascript
复制
BEGIN
    DBMS_SCHEDULER.RUN_JOB(
      JOB_NAME            => 'j1a,j2a'
      , USE_CURRENT_SESSION => FALSE
);
end;
/

看哪!下面是dbms_output:

代码语言:javascript
复制
MSG_PIPE listening
Message received: P#1:1
Message received: P#2:10
Message received: P#2:9
Message received: P#1:2
Message received: P#2:8
Message received: P#1:3
Message received: P#2:7
Message received: P#1:4
Message received: P#1:5
Message received: P#2:6
Message received: P#2:5
Message received: P#1:6
Message received: P#1:7
Message received: P#2:4
Message received: P#2:3
Message received: P#1:8
Message received: P#1:9
Message received: P#2:2
Message received: P#2:1
Message received: P#1:10
Message received: STOP
MSG_PIPE stopped

因此,很明显,这些过程是并行运行的,但消息并没有整齐地交错。当我们运行自主并行作业时,这是不可避免的,而会话之间没有任何交互作用。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59588772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档