如何不同步和独立于客户端应用程序运行Oracle存储过程



我已经实施了一个存储过程,该过程基于transaction_table中的数据生成CSV报告,并将生成的报告存储在report_table中以供将来参考。
我在Java程序中使用JPA执行并将参数传递给此过程,并且效果很好。

问题是:

  • 由于我们在transaction_table中有大量的交易数据,因此生成报告需要一些时间。在此期间,负责生成报告的弹出线程被阻止。
  • 如果用于运行该过程的数据库连接在执行的中间被打破,甚至我们都没有得到报告,但是负责处理请求的数据库线程未完成,并且在某些未知的内存中仍保留在内存中状态。因此,我们需要在执行时间内与数据库有主动连接。

我的问题是:

  1. 是否有任何方法可以立即调用过程并立即返回,而无需在存储过程的整个执行时间内阻止应用程序中的线程。
  2. 由于有可能失去数据库连接,是否有任何方法可以从正在调用它的应用程序中运行该过程独立连接。

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

我有 Oracle数据库11G企业版版本11.2.0.4.0-64bit Production ,在服务器上运行。

我确实提出了解决此问题的解决方案。因此,我决定分享它,以防您有类似的问题。

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

解决方案:
简短答案是:我创建了另一个过程(包装程序),该过程创建并启动dbms_schedule job (带有某些随机名称),该(随机名称)运行DBMS_SCHEDULE程序运行主过程。由于包装器的过程在毫秒内完成,因此不会阻止DB连接到长时间,因此可能会失败。

长答案:
步骤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;

希望它有帮助!

相关内容

最新更新