Как выполнять хранимые процедуры оракула асинхронно и независимо от клиентского приложения? - PullRequest
0 голосов
/ 03 марта 2019

Я реализовал хранимую процедуру, которая генерирует отчет CSV на основе данных в transaction_table и сохраняет сгенерированный отчет в report_table для будущих ссылок.
Я выполняю и передаю аргументы этой процедуре с использованием JPAв Java-программе, и она прекрасно работает.

Проблемы:

  • , поскольку у нас огромное количество данных транзакций в transaction_table, создание отчета занимает некоторое время,И в течение этого времени всплывающий поток, отвечающий за генерацию отчета, блокируется.
  • Если соединение с базой данных для запуска процедуры прерывается в середине выполнения, даже отчет мы не получаем, нотакже поток базы данных, отвечающий за обработку запроса, не завершается и остается в памяти в каком-то неизвестном состоянии. Поэтому нам необходимо активное соединение с базой данных во время выполнения.

Мои вопросы:

  1. Есть ли способ вызвать процедуру и немедленно вернуться, не блокируя поток в приложении на все время выполнения хранимой процедуры.
  2. Поскольку существует вероятность потери соединения с базой данных, существует ли какой-либо способ, которым база данных может запустить процедуру независимо из приложения, которое ее вызывает, чтобы завершить ее даже вотсутствие активного соединения.

Обратите внимание, что Мне нужно передать параметры отчета из приложения в процедуру.

У меня есть Oracle Database 11g Enterprise EditionВыпуск 11.2.0.4.0 - 64-битное производство , работающее на сервере.

1 Ответ

0 голосов
/ 06 марта 2019

Я нашел решение этой проблемы.поэтому я решил поделиться им, если у вас возникла подобная проблема.

Прежде всего позвольте мне подробнее объяснить проблему, а затем поделиться решением.
Проблема заключалась в следующем: я использую пул соединений в JPA дляподключиться к базе данных, и я использую аннотации JPA для выполнения процедуры в базе данных (я выполняю процедуру в отдельном потоке на стороне приложения).Запрос имеет дело с транзакциями для генерации массивного отчета, поэтому для его выполнения требуется некоторое время.Когда по какой-либо причине соединение с базой данных, которое было получено из пула, разрывается, даже если процедура базы данных не завершается, но также она не завершается сбоем, так что, по крайней мере, она освобождает ресурсы, которые у нее есть в руках.

Решение:
Краткий ответ : я создал другую процедуру ( процедура-обертка ), которая создает и запускает dbms_schedule job (с некоторым произвольным именем), который запускает программу dbms_schedule , которая запускает основную процедуру.Поскольку процедура оболочки завершается за считанные миллисекунды, она не блокирует соединение db на long, так что оно может потерпеть неудачу.

Длинный ответ:
Шаг 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;

надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...