当前位置: 代码迷 >> java >> 如何独立于客户端应用程序异步运行 oracle 存储过程?
  详细解决方案

如何独立于客户端应用程序异步运行 oracle 存储过程?

热度:85   发布时间:2023-07-25 20:09:22.0

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

问题是:

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

我的问题是:

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

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

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

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

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

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

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

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;

希望能帮助到你!

  相关解决方案