Sal*_*dor 30 sql oracle plsql oracle11g
我需要在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;
Run Code Online (Sandbox Code Playgroud)
我以这种方式打电话
SELECT TEST_SLEEP(10.5) FROM DUAL
Run Code Online (Sandbox Code Playgroud)
但要工作,我需要设置授予DBMS_LOCK程序的所有者.
如何在不使用该功能的情况下重写此DBMS_LOCK.sleep功能?
OMG*_*ies 41
如果没有授予权限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;
Run Code Online (Sandbox Code Playgroud)
Mat*_*son 22
创建一个只执行锁定并将其安装到使用dbms_lock(USERA)"信任"的其他用户的过程,授予USERA访问dbms_lock的权限.
然后只授予USERB访问此功能的权限.然后他们不需要能够访问DBMS_LOCK
(在运行之前,请确保系统中没有usera和userb)
以具有dbms_lock的grant privs的用户身份进行连接,并可以创建用户
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 */
Run Code Online (Sandbox Code Playgroud)
如果在"sqlplus"中执行,则可以执行主机操作系统命令"sleep":
!sleep 1
Run Code Online (Sandbox Code Playgroud)
要么
host sleep 1
Run Code Online (Sandbox Code Playgroud)
有一篇关于这个主题的好文章:PL/SQL: Sleep without using 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;
/
Run Code Online (Sandbox Code Playgroud)
选项 2:java.lang.Thread.sleep
另一种选择是使用 Java 类“Thread”中的方法“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;
/
Run Code Online (Sandbox Code Playgroud)
在Oracle 18c中,您可以使用DBMS_SESSION.SLEEP过程:
此过程将会话挂起指定的时间段。
Run Code Online (Sandbox Code Playgroud)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;
Run Code Online (Sandbox Code Playgroud)
过程包装的 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)';
Run Code Online (Sandbox Code Playgroud)