【问题标题】:How to run oracle stored procedures asynchronously and independently from client application?如何独立于客户端应用程序异步运行 oracle 存储过程?
【发布时间】:2019-07-24 19:01:19
【问题描述】:

我已经实现了一个存储过程,它根据 transaction_table 中的数据生成 csv 报告,并将生成的报告存储在 report_table 中以供将来参考。
我在 java 程序中使用 JPA 执行并将参数传递给此过程,它工作得非常好。

问题是:

  • 由于transaction_table中有大量交易数据,生成报告需要一些时间。并且在此期间负责生成报告的弹出线程被阻塞。
  • 如果运行过程的数据库连接在执行过程中中断,即使我们没有得到报告,而且负责处理请求的数据库线程也没有完成,并且在某些未知的情况下保留在内存中状态。所以我们需要在执行期间与数据库建立活动连接。

我的问题是:

  1. 有什么方法可以调用过程并立即返回,而不会在存储过程的整个执行时间内阻塞应用程序中的线程。
  2. 由于有可能丢失数据库连接,数据库是否可以通过任何方式独立从调用它的应用程序运行该过程,以便即使在没有活动的情况下也能完成连接。

请注意我需要将报告参数从应用程序传递到过程。

我有Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production,在服务器上运行。

【问题讨论】:

  • 您可以为此使用工作(dbms_scheduler)。
  • 实际上在我的研究中我遇到了这个答案link,但我不知道如何将参数从java应用程序传递给它并执行它!
  • 嗯。在您的问题开始时,您说“我已经实现了一个存储过程......我使用 JPA 执行并将参数传递给这个过程”。那么调用启动后台作业的存储过程有什么不同呢?

标签: java oracle stored-procedures spring-data-jpa


【解决方案1】:

我确实想出了解决这个问题的办法。所以我决定分享它,以防你有类似的问题。

首先让我进一步解释问题,然后分享解决方案。
问题是:我在 JPA 中使用连接池连接到数据库,并使用 JPA 注释在数据库上执行过程(我在应用程序端的单独线程中执行过程)。该查询正在处理生成大量报告的事务,因此执行需要一些时间。无论出于何种原因,从池中获得的数据库连接被破坏,即使数据库过程没有完成,但它也没有失败,因此至少它释放了它手头的资源.

解决方案:
简短的回答是:我创建了另一个过程(包装过程),它创建并启动 dbms_schedule 运行 dbms_schedule program 的作业(带有一些随机名称),该 program 运行主程序。由于包装程序在几毫秒内完成,它不会长时间阻塞数据库连接,因此它可能会失败。

长答案:
第 1 步:创建程序。

BEGIN
DBMS_SCHEDULER.create_program(
    program_name => 'DBUSER.PROG_NAME',
    program_action => 'DBUSER.MAIN_REPORT',
    program_type => 'STORED_PROCEDURE',
    number_of_arguments => 1, //number of passed arguments to procedure
    comments => NULL,
    enabled => FALSE);

//Do this for each argument    
DBMS_SCHEDULER.define_program_argument(
    program_name => 'DBUSER.PROG_NAME',
    argument_name => NULL,
    argument_position => 1,
    argument_type => 'VARCHAR2',
    out_argument => FALSE);

passing procedure arguments
DBMS_SCHEDULER.ENABLE(name=>'DBUSER.PROG_NAME');    
END;

第 2 步:创建 包装程序

create or replace PROCEDURE WRAPPER_PROC 
(
  FIRST_ARG IN VARCHAR2 
) 
IS
  job_name_var VARCHAR2(20);
BEGIN

  //creating a random job-name
  select DBMS_SCHEDULER.generate_job_name ('TEMP_JOB_') INTO job_name_var from dual;
  //creating the job
  dbms_scheduler.create_job(job_name      =>  job_name_var ,
                          program_name    =>  'PROG_NAME',
                          start_date      =>  systimestamp,
                          auto_drop       =>  true,
                          repeat_interval =>  null,
                          end_date        =>  null);
  //passing the argument to job                        
  dbms_scheduler.set_job_argument_value(job_name_var, 1, FIRST_ARG);
  //specifying the the dbms should drop the job after it has run
  dbms_scheduler.set_attribute(job_name_var,'max_runs',1);

  dbms_scheduler.enable(job_name_var);

  DBMS_OUTPUT.put_line('Job has successfully created');

END WRAPPER_PROC;

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 2013-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    • 2012-06-27
    • 2011-04-08
    相关资源
    最近更新 更多