OracleでSQLクエリを実行する必要がありますが、ある程度の時間がかかります。だから私はこの関数を書いた:
CREATE OR REPLACE FUNCTION MYSCHEMA.TEST_SLEEP
(
TIME_ IN NUMBER
)
RETURN INTEGER IS
BEGIN
DBMS_LOCK.sleep(seconds => TIME_);
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RAISE;
RETURN 1;
END TEST_SLEEP;
そして、私はこの方法で呼び出します
SELECT TEST_SLEEP(10.5) FROM DUAL
しかし、機能するには、プロシージャの所有者にDBMS_LOCK
の付与を設定する必要があります。
DBMS_LOCK.sleep
関数を使用せずにこの関数を書き換えるにはどうすればよいですか?
DBMS_LOCK.sleep
へのアクセスを許可する以外は、これは機能しますが、恐ろしいハックです。
IN_TIME INT; --num seconds
v_now DATE;
-- 1) Get the date & time
SELECT SYSDATE
INTO v_now
FROM DUAL;
-- 2) Loop until the original timestamp plus the amount of seconds <= current date
LOOP
EXIT WHEN v_now + (IN_TIME * (1/86400)) <= SYSDATE;
END LOOP;
ロックを行うだけのプロシージャを作成し、dbms_lock(USERA)で「信頼されている」別のユーザーにインストールし、dbms_lockへのUSERAアクセスを許可します。
次に、この関数へのUSERBアクセスを許可します。その後、DBMS_LOCKにアクセスできる必要はありません。
(これを実行する前に、システムにuseraとuserbがないことを確認してください)
Dbms_lockの付与特権を持つユーザーとして接続し、ユーザーを作成できます
drop user usera cascade;
drop user userb cascade;
create user usera default tablespace users identified by abc123;
grant create session to usera;
grant resource to usera;
grant execute on dbms_lock to usera;
create user userb default tablespace users identified by abc123;
grant create session to userb;
grant resource to useb
connect usera/abc123;
create or replace function usera.f_sleep( in_time number ) return number is
begin
dbms_lock.sleep(in_time);
return 1;
end;
/
grant execute on usera.f_sleep to userb;
connect userb/abc123;
/* About to sleep as userb */
select usera.f_sleep(5) from dual;
/* Finished sleeping as userb */
/* Attempt to access dbms_lock as userb.. Should fail */
begin
dbms_lock.sleep(5);
end;
/
/* Finished */
「sqlplus」内で実行すると、ホストオペレーティングシステムコマンド「sleep」を実行できます。
!sleep 1
または
Host sleep 1
Oracle 18cからDBMS_SESSION.SLEEPプロシージャを使用できます。
このプロシージャは、指定された期間セッションを一時停止します。
DBMS_SESSION.SLEEP (seconds IN NUMBER)
DBMS_SESSION.sleep
は、追加の許可なしですべてのセッションで使用できます。 DBMS_LOCK.sleep
は廃止されることに注意してください。
単純なクエリスリープが必要な場合は、WITH FUNCTION
を使用できます。
WITH FUNCTION my_sleep(i NUMBER)
RETURN NUMBER
BEGIN
DBMS_SESSION.sleep(i);
RETURN i;
END;
SELECT my_sleep(3) FROM dual;
Javaプロシージャでラップされたコード?シンプルで問題なく動作します。
CREATE OR REPLACE AND COMPILE Java SOURCE NAMED SNOOZE AS
public final class Snooze {
private Snooze() {
}
public static void snooze(Long milliseconds) throws InterruptedException {
Thread.sleep(milliseconds);
}
}
CREATE OR REPLACE PROCEDURE SNOOZE(p_Milliseconds IN NUMBER) AS
LANGUAGE Java NAME 'Snooze.snooze(Java.lang.Long)';
このトピックに関する良い記事があります: PL/SQL:DBMS_LOCKを使用せずにスリープ 助けてくれました。カスタムパッケージにラップされたオプション2を使用しました。提案されたソリューションは次のとおりです。
オプション1:APEX_UTIL.sleep
APEXがインストールされている場合、公開されているパッケージAPEX_UTILの手順「PAUSE」を使用できます。
例–「5秒間待つ」:
SET SERVEROUTPUT ON ;
BEGIN
DBMS_OUTPUT.PUT_LINE('Start ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
APEX_UTIL.PAUSE(5);
DBMS_OUTPUT.PUT_LINE('End ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
END;
/
オプション2:Java.lang.Thread.sleep
もう1つのオプションは、Javaクラス「スレッド」からのメソッド「sleep」の使用です。これは、単純なPL/SQLラッパープロシージャを提供することで簡単に使用できます。
注:「Thread.sleep」ではミリ秒が使用されることに注意してください。
--- create ---
CREATE OR REPLACE PROCEDURE SLEEP (P_MILLI_SECONDS IN NUMBER)
AS LANGUAGE Java NAME 'Java.lang.Thread.sleep(long)';
--- use ---
SET SERVEROUTPUT ON ;
BEGIN
DBMS_OUTPUT.PUT_LINE('Start ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
SLEEP(5 * 1000);
DBMS_OUTPUT.PUT_LINE('End ' || to_char(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
END;
/
同期メカニズムを実装することをお勧めします。最も簡単なのは、最初のファイルが完了した後にファイルを書き込むことです。これで、センチネルファイルができました。
そのため、外部プログラムは、存在するセンチネルファイルを探します。実行すると、実際のファイルのデータを安全に使用できることがわかります。
これを行う別の方法は、一部のブラウザーがファイルをダウンロードするときに行う方法に似ていますが、ファイルが完全にダウンロードされるまでbase-name_partという名前のファイルを作成し、最後にファイルの名前をbase-nameに変更します。このようにして、外部プログラムは、完了するまでファイルを「見る」ことができません。この方法では、外部プログラムを書き直す必要はありません。これはこの状況に最適かもしれません。
DBMS_PIPE.SEND_MESSAGE
は、パイプに対して大きすぎるメッセージで使用できます。たとえば、5秒の遅延の場合、次のように5秒のタイムアウトを使用して1バイトしか受け入れられないパイプにXXXを書き込みます。
dbms_pipe.pack_message('XXX');<br>
dummy:=dbms_pipe.send_message('TEST_PIPE', 5, 1);
ただし、その場合はDBMS_PIPE
の許可が必要なので、おそらくそれ以上のことはありません。
DBMS_ALERT
パッケージは次のように使用できます。
CREATE OR REPLACE FUNCTION sleep(seconds IN NUMBER) RETURN NUMBER
AS
PRAGMA AUTONOMOUS_TRANSACTION;
message VARCHAR2(200);
status INTEGER;
BEGIN
DBMS_ALERT.WAITONE('noname', message, status, seconds);
ROLLBACK;
RETURN seconds;
END;
SELECT sleep(3) FROM dual;
Javaが11Gにインストールされている場合、Javaクラスでそれを実行し、PL/SQLから呼び出すことができますが、 Javaを呼び出すための特定の許可も必要ありません。
Javaプロシージャ/関数が機能する可能性があります。しかし、アプリケーションスキーマやこの許可を持つ管理者アカウントなどのユーザーの下で関数をコンパイルし、開発者アカウントにそのようにして、定義者権限が使用されます。