OCP課程58:管理II之自動任務

stonebox1122發表於2017-04-14

課程目標:

  • 使用排程程式簡化管理
  • 建立作業,程式和排程
  • 監控作業執行
  • 使用基於時間和基於事件的排程執行排程程式作業
  • 視窗,視窗組,作業類和使用者組
  • 使用郵件通知
  • 使用作業鏈執行一系列相關任務
  • 在遠端系統上的排程程式作業
  • 使用高階排程程式概念來區分作業的優先順序

1、簡化管理

clipboard

  • 在每個月最後一天執行一系列月末任務
  • 訊息入隊後立即執行出隊過程
  • 透過重新整理物化檢視複製表資料
  • 執行每天的資料庫備份任務
  • 每天計算兩次表和索引統計資訊
  • 檔案到達檔案系統後立即啟動成批裝入
  • 每小時生成一個有關無效伺服器訪問嘗試的報表
  • 重建完當前索引後重建另一索引

Oracle 環境中的許多工都需要作業排程功能。例行的資料庫維護和應用程式邏輯要求定期排程並執行作業。企業到企業(B2B) 應用程式要求對其業務事件進行排程。DBA需要在指定時間視窗中排程日常維護作業。

Oracle資料庫透過資料庫排程程式提供高階排程功能,此排程程式是DBMS_SCHEDULER程式包中函式和過程的集合。可以在任何SQL 環境中,或者透過EM來呼叫此排程程式。

使用此排程程式,資料庫管理員和應用程式開發者可以控制在資料庫環境中執行各種任務的時間和位置。這些任務可能既耗時又複雜;可以使用排程程式來管理和計劃這些任務。

可以根據時間或者在發生指定事件時啟動排程程式作業,而且排程程式還可以在作業狀態更改時(例如,從RUNNING變為COMPLETE)引發事件。還可以使用為達到組合目標而連結在一起的一系列已命名的程式。


2、核心元件

clipboard[1]

核心元件和主要步驟

一個作業包含兩個必需元件:需要執行的操作,操作的發生時間或排程。“操作”是由命令區域和作業屬性中的job_type和job_action參數列示的。“時間”是在排程中表示的,排程可以基於時間或事件,或者從屬於其它作業的結果。

排程程式使用以下基本元件:

? “作業(job)”指定要執行的操作。它可以是PL/SQL過程、純二進位制可執行檔案、Java應用程式或Shell指令碼。可以將程式(內容)和排程(時間)指定為作業定義的一部分,也可以改用現有的程式或排程。可以使用作業的引數來定製其執行時行為。

? “排程(schedule)”指定作業的執行時間和次數。排程可以基於時間或事件。可以為作業定義排程,方法是使用一系列日期、一個事件,或兩者相結合,以及表示重複間隔的附加說明。可以單獨儲存作業的排程,然後對多個作業使用同一個排程。

? “程式(program)”是有關特定可執行檔案、指令碼或過程的後設資料集合。自動作業將執行某個任務。使用程式,無需修改作業本身即可修改作業任務或者“內容”。可以定義程式的引數,使使用者可以修改任務的執行時行為。


3、基本工作流

clipboard[2]

使用排程程式來簡化管理任務:

(1) 建立程式(啟用或禁用)- 可選

– 在多個作業中重用此操作

– 在無需重新建立PL/SQL 塊的情況下更改作業的排程

(2)建立並使用排程

(3)建立並提交作業

可以在EM的圖形環境中執行所有步驟,或者透過命令列使用DBMS_SCHEDULER PL/SQL包執行所有步驟。

(1) 建立程式

使用CREATE_PROGRAM過程來建立程式。使用排程程式時,建立程式是一個可選部分。還可以對操作進行編碼,使其在CREATE_JOB過程的匿名PL/SQL塊中執行。透過單獨建立程式,可以定義一次操作,然後在多個作業中重用此操作。使用這種方法,無須重新建立PL/SQL塊即可更改作業的排程。

預設情況下,程式是以禁用狀態建立的(除非enabled引數設為TRUE)。在將禁用的程式啟用之前,作業無法執行此程式。可以透過將enabled的值指定為TRUE來指定應以啟用狀態建立程式。

(2)建立並使用排程

作業的排程可以是預定義的排程(用CREATE_SCHEDULE過程建立的),也可以是在建立作業時定義的。

排程指定有關作業執行的屬性,例如:

? 起始時間,定義作業從哪一時間開始執行;結束時間,指定作業在哪一時間之後失效且不再進行排程

? 指定作業重複間隔的表示式

? 透過組合現有排程建立的複雜排程

? 啟動作業之前必須滿足的條件或狀態變化(稱為事件)

透過使用排程(而不是在作業定義中指定作業的執行次數),可以管理多個作業的預定執行,而無須更新多個作業定義。如果修改了某個排程,則使用該排程的每個作業都將自動使用新排程。

(3)建立並執行作業

作業是一個組合,其中包括排程、要執行的操作的說明以及作業需要的所有附加引數。可以為作業設定許多屬性,用於控制作業的執行方式。

例子:建立作業

建立表和PL/SQL BLOCK

SQL> create table emprownum(time date,num number);

Table created.

SQL> insert into emprownum select sysdate,count(*) from employees;

1 row created.

SQL> select * from emprownum;

TIME                      NUM

------------------ ----------

20-AUG-16                 107

declare

begin

insert into emprownum select sysdate,count(*) from employees;

end;

建立程式

clipboard[3]

clipboard[4]

BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM(
program_name=>'"SYS"."EMPROWNUM"',
program_action=>'declare
begin
insert into emprownum select sysdate,count(*) from employees;
end;',
program_type=>'PLSQL_BLOCK',
number_of_arguments=>0,
comments=>'',
enabled=>TRUE);
END;


clipboard[5]

建立排程:

clipboard[6]

clipboard[7]

clipboard[8]

BEGIN
sys.dbms_scheduler.create_schedule(
repeat_interval=>'FREQ=HOURLY',
start_date=>systimestampattimezone'Asia/Shanghai',
end_date=>to_timestamp_tz('2016-08-21 17:50:00 Asia/Shanghai','YYYY-MM-DD HH24:MI:SS TZR'),
schedule_name=>'"SYS"."EMPROWNUM"');
END;


clipboard[9]

clipboard[10]

建立作業

clipboard[11]

clipboard[12]

clipboard[13]

clipboard[14]

BEGIN
sys.dbms_scheduler.create_job(
job_name=>'"SYS"."HREMPROWNUMJOB"',
program_name=>'"SYS"."EMPROWNUM"',
schedule_name=>'"SYS"."HREMPROWNUM"',
job_class=>'"DEFAULT_JOB_CLASS"',
auto_drop=>FALSE,
enabled=>TRUE);
END;


clipboard[15]

clipboard[16]


4、持久輕量作業

clipboard[17]

持久輕量作業:

? 減少啟動作業所需的開銷和時間

? 作業後設資料和執行時資料在磁碟上佔用很小的空間

? 是使用作業模板(在命令列中)建立的

BEGIN

DBMS_SCHEDULER.CREATE_JOB (

job_name => 'my_lightweight_job2',

program_name=>'"SYS"."EMPROWNUM"',
schedule_name=>'"SYS"."HREMPROWNUM"',

job_style => 'LIGHTWEIGHT');

END;

/

選擇合適的作業型別:

–使用常規作業可提供最大靈活性。

–需要在很短的時間內建立大量作業時,請使用持久輕量作業。

輕量作業:

? 適合需要在一秒內建立數百個作業的客戶。對於常規作業,每個作業都要建立一個資料庫物件,用於描述作業、修改多個表以及生成重做。此種型別作業需求的相關開銷是很大的。在Oracle資料庫排程程式中,有一種“持久輕量作業”。輕量作業的目的是減少啟動作業所需的開銷和時間。將為作業建立極少的後設資料。這可以減少啟動作業時所需的時間和建立的重做。

? 作業後設資料和執行時資料在磁碟上佔用很小的空間。在磁碟上佔用的空間小還可實現在RAC 環境中進行負載平衡。

? 始終是使用作業模板建立的。作業模板必須是一個儲存過程或一個程式。儲存過程可以儲存作業所需的所有資訊,包括許可權。只可以指定少量作業屬性:作業引數和排程。

? 必須在命令列中建立。JOB_STYLE引數在EM 中不可用。

在示例中,MY_PROG是作業模板,排程是透過已命名的排程應用的。

例子:使用前面建立的程式和排程建立輕量作業

SQL> BEGIN

  2  DBMS_SCHEDULER.CREATE_JOB (

  3  job_name => 'my_lightweight_job2',

  4  program_name=>'"SYS"."EMPROWNUM"',

  5  schedule_name=>'"SYS"."HREMPROWNUM"',

  6  job_style => 'LIGHTWEIGHT');

  7  END;

  8  /

PL/SQL procedure successfully completed.

clipboard[18]

clipboard[19]


BEGIN
sys.dbms_scheduler.enable('"SYS"."MY_LIGHTWEIGHT_JOB2"');
END;


clipboard[20]


5、使用基於時間或者基於事件的排程

clipboard[21]

要為作業指定基於時間的排程,可以指定日曆表示式或日期時間表示式。使用日曆表示式時,將使用作業的重複間隔和起始日期來計算作業的下一啟動時間。使用日期時間表示式時,指定的表示式確定作業下次應執行的時間。如果沒有指定重複間隔,作業將只在指定的起始日期執行一次。

如果作業使用基於事件的排程,作業將在事件發生時執行。在較高層次上,可以將事件視為狀態的更改。布林條件的狀態從FALSE更改為TRUE,或者從TRUE更改為FALSE時,將發生事件。

排程程式使用Oracle Streams Advanced Queuing (AQ)來引發和使用事件。

注:排程程式不保證作業恰好在計劃的時間執行,因為可能會由於系統過載而造成資源不可用。


6、建立一個基於時間的任務

clipboard[22]

示例:建立一個作業,從今晚起在每晚11:00 呼叫備份指令碼。

BEGIN

DBMS_SCHEDULER.CREATE_JOB(

job_name=>'HR.DO_BACKUP',

job_type=> 'EXECUTABLE',

job_action=>

'/home/usr/dba/rman/nightly_incr.sh',

start_date=> SYSDATE,

repeat_interval=>'FREQ=DAILY;BYHOUR=23',

/* next night at 11:00 PM */

comments => 'Nightly incremental backups');

END;

/

建立基於時間的作業

可以使用DBMS_SCHEDULER程式包的CREATE_JOB過程來建立作業。預設情況下將以禁用狀態建立作業,僅當顯式啟用時,這些作業才生效並可以排程。所有作業名稱都採用以下形式:[schema.]name。

應該使用SYSTIMESTAMP並指定時區,這樣當時間因夏令時更改時,作業能夠自動調整其執行時間。

預設情況下,將在當前模式中建立作業。可以透過指定模式的名稱在另一個模式中建立作業,如示例所示。作業所有者是在其模式中建立作業的使用者,而作業建立者是建立作業的使用者。作業將按作業所有者的許可權來執行。作業執行時的國家語言支援(NLS) 環境與建立作業時的環境相同。job_type引數指示作業將要執行的任務的型別。可能的值包括:

? PLSQL_BLOCK:匿名PL/SQL塊

? STORED_PROCEDURE:命名的PL/SQL、Java 或外部過程

? EXECUTABLE:可以從作業系統(OS)命令列執行的命令

job_action引數可以是要執行的過程的名稱、指令碼的名稱或作業系統命令的名稱,也可以是匿名的PL/SQL程式碼塊,具體取決於job_type引數的值。

在示例中,job_type被指定為EXECUTABLE,job_action是所需的外部可執行檔案加上任何命令列引數(可選)的作業系統相關完整路徑。

外部作業是指在資料庫外部執行的作業。所有外部作業均作為低許可權的來賓使用者執行,這一點已在資料庫管理員配置外部作業支援時確定。因為可執行檔案作為低許可權的來賓帳戶執行,所以應確保其有權訪問必要的檔案和資源。大多數(但不是所有)平臺都支援外部作業。對於不支援外部作業的平臺,如果將作業或程式的屬性建立或設定為EXECUTABLE型別,將返回錯誤。

例子:建立一個基於時間的作業

先建立一個指令碼

[ ~]$ cat /home/oracle/delarch.sh

#!/bin/bash

rman target / <<eof </eof<>

crosscheck archivelog all;

delete noprompt expired archivelog all;

exit

EOF

建立作業

clipboard[23]

clipboard[24]

clipboard[25]

clipboard[26]

clipboard[27]


BEGIN
sys.dbms_scheduler.create_job(
job_name=>'"SYS"."JOB1"',
job_type=>'EXECUTABLE',
job_action=>'/home/oracle/delarch.sh',
repeat_interval=>'FREQ=DAILY;BYHOUR=13;BYMINUTE=0;BYSECOND=0',
start_date=>systimestampattimezone'Asia/Shanghai',
end_date=>to_timestamp_tz('2016-08-24 Asia/Shanghai','YYYY-MM-DD TZR'),
job_class=>'"DEFAULT_JOB_CLASS"',
auto_drop=>FALSE,
enabled=>TRUE);
END;


clipboard[28]

clipboard[29]


7、建立一個基於事件的排程

clipboard[30]

要建立基於事件的作業,必須設定:

? 佇列說明(應用程式將訊息入隊以啟動作業)

? 一個事件條件(與Oracle Streams AQ規則條件的語法相同),如果為TRUE則啟動作業

可以基於事件觸發作業。應用程式可以通知排程程式啟動作業,方法是將訊息入隊到Oracle Streams佇列中。以這種方法啟動的作業稱為基於事件的作業。要建立基於事件的作業,必須用CREATE_JOB過程設定以下兩個附加屬性:

? queue_spec:對佇列的指定,包括應用程式將訊息放入其中以引發作業啟動事件的佇列的名稱;對於安全佇列,則為,對。

? event_condition:基於訊息屬性的條件表示式,此表示式的求值結果必須為TRUE,訊息才能啟動作業。只要訊息有效負載是使用者定義的物件型別,並且將表示式中的物件屬性加了tab.user_data字首,就可以在表示式中包含使用者資料屬性。

可以將queue_spec和event_condition指定為內嵌作業屬性,或者用這兩個屬性建立基於事件的排程,然後建立一個引用此排程的作業。


8、使用EM建立基於事件的排程

clipboard[31]

使用“Create Schedule(建立排程)”頁,可以從標準的、基於時間的排程和基於事件的排程之中選擇一種來建立。如果選擇基於事件的排程,可以指定佇列名、代理名和事件條件以及其它排程屬性。

注意:對於與event_condition匹配的事件的每次發生,排程程式都會執行基於事件的作業。但是,在作業執行過程中發生的事件將會被忽略;事件繼續執行,但不會觸發作業再次執行。

例子:使用EM建立基於事件的排程

建立佇列代理並關聯佇列

SQL> EXEC DBMS_AQADM.CREATE_AQ_AGENT(agent_name => 'ADMIN_AGNT1');

PL/SQL procedure successfully completed.

SQL> DECLARE

  subscriber SYS.AQ$_AGENT;

BEGIN

subscriber :=  SYS.AQ$_AGENT('ADMIN_AGNT1', NULL, NULL);

DBMS_AQADM.ADD_SUBSCRIBER(

    queue_name          =>  'ALERT_QUE',

subscriber          =>  subscriber,

    rule                =>  NULL,

    transformation      =>  NULL);

END;

/

PL/SQL procedure successfully completed.

SQL>BEGIN

DBMS_AQADM.ENABLE_DB_ACCESS(

agent_name  => 'ADMIN_AGNT1',

db_username => 'SYS');

END;

/

PL/SQL procedure successfully completed.

DECLARE

  subscriber SYS.AQ$_AGENT;

BEGIN

subscriber :=  SYS.AQ$_AGENT('ADMIN_AGNT1', NULL, NULL);

DBMS_AQADM.ADD_SUBSCRIBER(

    queue_name          =>  'SCHEDULER_FILEWATCHER_Q',

subscriber          =>  subscriber,

    rule                =>  NULL,

    transformation      =>  NULL);

END;

/

clipboard[32]

clipboard[33]


BEGIN
sys.dbms_scheduler.create_event_schedule(
event_condition=>'''tab.user_data.event_type="DISK_FULL"''',
queue_spec=>'"SYS"."ALERT_QUE","ADMIN_AGNT1"',
start_date=>to_timestamp_tz('2016-08-21 22:20:00 Asia/Shanghai','YYYY-MM-DD HH24:MI:SS TZR'),
schedule_name=>'"SYS"."SCH1"');
END;


clipboard[34]


10、建立一個基於事件的作業

clipboard[35]

示例:建立一個作業,如果成批裝入的資料檔案在上午9:00 前到達檔案系統,則執行此作業。

BEGIN

DBMS_SCHEDULER.CREATE_JOB(

job_name=>'ADMIN.PERFORM_DATA_LOAD',

job_type => 'EXECUTABLE',

job_action => '/loaddir/start_my_load.sh',

start_date => SYSTIMESTAMP,

event_condition => 'tab.user_data.object_owner =

''HR'' and tab.user_data.object_name = ''DATA.TXT''

and tab.user_data.event_type = ''FILE_ARRIVAL''

and tab.user_data.event_timestamp < 9 ',

queue_spec => 'HR.LOAD_JOB_EVENT_Q');

END;

建立基於事件的作業

要將事件資訊指定為作業屬性,請使用CREATE_JOB的替代語法,其中包括queue_spec和event_condition屬性。作業可以包含作為作業屬性的內嵌事件資訊,或可以透過指向事件排程來指定事件資訊。顯示的示例使用了內嵌的基於事件的排程。

示例顯示了一個作業,只要有檔案在上午9:00 前到達作業系統,就會啟動此作業。假定訊息有效負載是一個物件,該物件包括四個名稱分別為object_owner、object_name、event_type和event_timestamp的屬性。

本例使用的是使用者定義的事件。因此,檔案在到達了檔案系統後,必須有一個程式或過程將包含正確資訊的事件物件型別入隊到指定的事件佇列中,才能啟動此作業。HR.LOAD_JOB_EVENT_Q佇列必須與用於將事件的發生通知排程程式的事件物件型別相同。即,HR.LOAD_JOB_EVENT_Q佇列必須是型別化佇列,其中的型別包括四個名稱為object_owner、object_name、event_type和event_timestamp的屬性。


11、基於事件的排程

clipboard[36]

事件型別:

? 使用者或應用程式生成的事件

? 排程程式生成的事件

由排程程式作業引發的事件:

? JOB_STARTED

? JOB_SUCCEEDED

? JOB_FAILED

? JOB_BROKEN

? JOB_COMPLETED

? JOB_STOPPED

? JOB_SCH_LIM_REACHED

? JOB_DISABLED

? JOB_CHAIN_STALLED

? JOB_ALL_EVENTS

? JOB_RUN_COMPLETED

? JOB_OVER_MAX_DUR

引發事件的示例:

DBMS_SCHEDULER.SET_ATTRIBUTE('hr.do_backup', 'raise_events', DBMS_SCHEDULER.JOB_FAILED);

基於事件的排程

你可以建立一個作業,但不向作業分配排程,而是透過直接引用事件來啟動作業。有兩種型別的事件:

? 使用者或應用程式生成的事件:應用程式可以引發由排程程式使用的事件。排程程式透過啟動作業來回應事件。此類事件的示例:正在執行的作業完成;檔案到達檔案系統;資料庫內的帳戶被鎖定;以及庫存到達下限閾值。

? 排程程式生成的事件:排程程式可以引發事件來指示在排程程式自身內發生的狀態更改。例如,在作業啟動時、作業完成時、作業超出其分配的執行時間時等條件下,排程程式均可以引發事件。事件的使用者是一個應用程式,該應用程式將執行某個操作以便對事件做出響應。

你可以對作業進行配置,使排程程式在作業的狀態更改時引發事件。可以透過設定raise_events作業屬性來完成此操作。預設情況下,在變更作業的raise_events屬性之前,作業不會引發任何狀態更改事件。要變更此屬性,必須先使用CREATE_JOB過程建立作業,然後使用SET_ATTRIBUTE過程修改此屬性的預設值。本例顯示hr.do_backup作業已變更,使得該作業在失敗時引發事件。

為作業啟用作業狀態更改事件後,排程程式將引發這些事件,方法是將訊息入隊到預設的事件佇列SYS.SCHEDULER$_EVENT_QUEUE中。

預設的排程程式事件佇列是一個安全佇列。可能需要配置佇列,才能允許特定使用者在此佇列上執行操作,具體取決於應用程式。檢視文件Oracle Streams Concepts and Administrator獲取關於安全佇列的詳細資訊。

預設的排程程式事件佇列主要用於排程程式生成的事件。Oracle 建議你不要將此佇列用於使用者應用程式或使用者定義的事件。

clipboard[37]


12、建立複雜排程

clipboard[38]

建立複雜排程

排程是資料庫中的物件。建立排程時,將自動儲存這些排程。可以使用排程的組合來建立更復雜的排程。透過組合排程,可以向日歷表示式中新增特定日期,或者從日曆表示式中排除特定日期。

定義排程的重複間隔時可以使用下列選項:

? INCLUDE:向日歷表示式結果中新增日期列表

? EXCLUDE:從日曆表示式結果中刪除日期列表

? INTERSECT:只使用兩個或多個排程共有的日期

建立要組合使用的排程時,可以對日期列表進行編碼,方法是包含形式為[YYYY]MMDD的硬編碼日期,或者包含用CREATE_SCHEDULE過程建立的已命名排程。例如,可以對排程的重複間隔使用下列值來指定日期列表:

0115,0315,0325,0615,quarter_end_dates,1215

此字串表示日期1 月15 日、3 月15 日、3 月25 日、6 月15 日、12 月15 日以及QUARTER_END_DATES排程所指定的日期列表。

如果未在排程中指定硬編碼日期的可選年份,則包括每一年的這些日期。


13、使用郵件通知

clipboard[39]

? 作業狀態更改的電子郵件通知

? 是由作業狀態事件觸發的

? 多個通知,多個收件人

? *_SCHEDULER_NOTIFICATIONS檢視

使用排程程式電子郵件通知:

1. 指定你將用來傳送電子郵件的SMTP 伺服器的地址:

DBMS_SCHEDULER.SET_SCHEDULER_ATTRIBUTE

('email_server','host[:port]');

2. 還可以設定預設的發件人電子郵件地址:

DBMS_SCHEDULER.SET_SCHEDULER_ATTRIBUTE

('email_sender','valid email address');

3. 為指定作業新增電子郵件通知。

使用作業電子郵件通知功能,可以向現有作業新增電子郵件通知,以便作業中發生受關注事件後向指定的電子郵件地址傳送通知。對於每個作業,可以為不同的事件新增通知。可以將電子郵件通知傳送給多個收件人。

要啟用電子郵件通知功能,你必須:

1.設定email_server排程程式屬性。

2.此外,還可以使用email_sender排程程式屬性指定電子郵件通知的預設發件人電子郵件地址。

3.建立作業後,執行DBMS_SCHEDULER.ADD_JOB_EMAIL_NOTIFICATION過程,為作業新增一個或多個通知。

資料字典透過*_SCHEDULER_NOTIFICATIONS檢視支援電子郵件通知。


14、增加和刪除郵件通知

clipboard[40]

DBMS_SCHEDULER.ADD_JOB_EMAIL_NOTIFICATION (

job_name  IN VARCHAR2,

recipients  IN VARCHAR2,---逗號分隔的電子郵件地址列表

sender  IN VARCHAR2 DEFAULT NULL,

subject IN VARCHAR2

DEFAULT dbms_scheduler.default_notification_subject,

body IN VARCHAR2

DEFAULT dbms_scheduler.default_notification_body,

events  IN VARCHAR2---必需的逗號分隔列表

DEFAULT 'JOB_FAILED,JOB_BROKEN,JOB_SCH_LIM_REACHED,

JOB_CHAIN_STALLED,JOB_OVER_MAX_DUR',

filter_condition  IN VARCHAR2 DEFAULT NULL);

DBMS_SCHEDULER.REMOVE_JOB_EMAIL_NOTIFICATION (

job_name  IN VARCHAR2,

recipients  IN VARCHAR2 DEFAULT NULL,

events  IN VARCHAR2 DEFAULT NULL);

新增和刪除電子郵件通知

使用DBMS_SCHEDULER.ADD_JOB_EMAIL_NOTIFICATION過程新增一個或多個作業電子郵件通知。只要作業生成了指定的任一事件,系統就會將電子郵件傳送至指定的收件人地址。如果指定了過濾條件,則只有與FILTER_CONDITION中的條件匹配的事件將生成電子郵件。

如果未設定EMAIL_SERVER排程程式屬性或指定的作業不存在,則該過程將失敗。呼叫該過程的使用者必須是作業的所有者,必須具有CREATE ANY JOB系統許可權,或已經被授予了對作業的ALTER許可權。

? 通知電子郵件的主題可以包含值將被替換的下列變數:%job_owner%、%job_name%、%event_type%、%event_timestamp%、%log_id%、

%error_code%、%error_message%、%run_count%、%failure_count%、%retry_count%、%job_subname%、%job_class_name%。

? 通知電子郵件的正文可以包含主題中有效的任何變數。

? 逗號分隔的事件列表不能為空。

? 如果filter_condition為空(預設值),則只要指定事件出現,系統就會向所有指定的收件人地址傳送通知。

使用DBMS_SCHEDULER.REMOVE_JOB_EMAIL_NOTIFICATION過程刪除指定作業的一個或多個電子郵件通知。


15、建立作業鏈

clipboard[41]

1. 建立鏈物件。

2. 定義鏈步驟。

3. 定義鏈規則。

4. 啟動鏈:

– 啟用鏈。

– 建立指向鏈的作業。

鏈是為達到組合目標而連結在一起的一系列已命名的程式。這被稱為“依存排程”。鏈的示例如下所示:

執行程式A然後執行程式B,如果程式A和程式B成功完成,則只執行程式C,否則執行程式D。

在相互依賴的程式構成的鏈中,每個位置都稱為一個步驟。通常情況下,鏈的一系列初始步驟啟動之後,後續步驟的執行依賴於一個或多個之前步驟的完成。要建立並使用鏈,請依次完成下列步驟。如果沒有特別說明,則提到的所有過程都是DBMS_SCHEDULER程式包的一部分。

1.使用CREATE_CHAIN過程建立鏈。可以選擇用模式名稱來限定鏈名稱(如myschema.myname)。

2.定義(一個或多個)鏈步驟。定義步驟時需要命名此步驟並指定步驟中發生的操作。

每個步驟都可以指向下列項之一:

- 程式

- 另一個鏈(巢狀鏈)

- 事件

透過呼叫DEFINE_CHAIN_STEP過程來定義指向程式或巢狀鏈的步驟。

要定義等待事件發生的步驟,請使用DEFINE_CHAIN_EVENT_STEP過程。過程引數可以指向事件排程,也可以包括內嵌佇列說明和事件條件。指向事件的步驟會一直等待,直到指定事件被引發。如果此事件發生,則步驟將成功完成。

3.建立鏈物件後,請定義鏈規則。鏈規則定義各步驟執行的時間,並定義各步驟之間的依賴關係。每個規則都有一個“條件”和一個“操作”:

- 如果條件的求值結果為TRUE,則執行操作。條件中可以包含在SQL WHERE子句中有效的任何語法。條件通常基於前面一個或多個步驟的結果。例如,你可能希望使某步驟在前兩個步驟全部成功的情況下執行,而使另一個步驟在前兩個步驟未全部成功的條件下執行。

- 操作指定在觸發規則時要執行的內容。

典型操作是執行指定的步驟。可能的操作包括啟動或停止步驟。還可以選擇結束作業鏈的執行、返回一個值或者返回步驟名和錯誤程式碼。

新增到鏈中的所有規則共同確定了鏈的整體行為。在作業啟動時以及在每個步驟結束時,將對所有規則求值以確定接下來發生的操作。請使用DEFINE_CHAIN_RULE過程向鏈中新增規則。向鏈中新增每個規則時均需要呼叫一次此過程。

4.啟動鏈包括兩個操作:

- 用ENABLE過程啟用鏈。(鏈總是以禁用狀態建立,因此可以在任何作業執行該鏈之前向其中新增步驟和規則。)啟用一個已啟用的鏈不會返回錯誤。

- 要執行鏈,必須建立'CHAIN'型別的作業。作業操作必須引用鏈名稱。可以為此作業使用基於事件的排程或基於時間的排程。


16、作業鏈示例

clipboard[42]

在此鏈示例中,請考慮在批次資料載入期間出現的所有任務和條件。首先,必須有要載入的資料。然後載入資料,同時觀察檔案系統以確保在載入期間不會發生空間不足的情況。在資料載入完成後,需要重建在更新後的表上定義的索引。然後針對新載入資料執行報表。該幻燈片顯示了一個依存排程示例。

例子:作業鏈

clipboard[43]

clipboard[44]

clipboard[45]

clipboard[46]

clipboard[47]

BEGIN
sys.dbms_scheduler.create_chain(
chain_name=>'"SYS"."JOBCHAIN2"');
sys.dbms_scheduler.define_chain_step(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC1"',
program_name=>'"SYS"."EMPROWNUM"');
sys.dbms_scheduler.alter_chain(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC1"',
attribute=>'pause',
value=>FALSE);
sys.dbms_scheduler.alter_chain(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC1"',
attribute=>'skip',
value=>FALSE);
sys.dbms_scheduler.define_chain_step(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC2"',
program_name=>'"SYS"."AUTO_SQL_TUNING_PROG"');
sys.dbms_scheduler.alter_chain(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC2"',
attribute=>'pause',
value=>FALSE);
sys.dbms_scheduler.alter_chain(
chain_name=>'"SYS"."JOBCHAIN2"',
step_name=>'"JOBC2"',
attribute=>'skip',
value=>FALSE);
sys.dbms_scheduler.define_chain_rule(
chain_name=>'"SYS"."JOBCHAIN2"',
condition=>'jobc1 SUCCEEDED',
action=>'START JOBC2');
END;

clipboard[48]


17、高階排程器概念

clipboard[49]

使用高階排程程式功能,可以對排程的各個方面施加更強的控制,例如作業視窗和區分作業優先順序。

? “視窗”由定義好起始時間和結束時間的時間間隔表示,用於在不同時間啟用不同的資源計劃。這使你可以更改某一時段(如一天或銷售年度內的某一時間段)的資源分配。

? “視窗組”表示一系列視窗,使用它可以更輕鬆地管理視窗。可以將視窗或視窗組用於作業的排程,以確保作業僅在視窗及其關聯資源計劃有效時執行。

? “作業類”定義了一類作業,這些作業具有共同的資源使用要求和其它特性。作業類將作業分組到更大的實體中。

? 與作業類關聯的“資源使用者組”確定分配給作業類中作業的資源。

? 使用“資源計劃”,使用者可以在各資源使用者組中區分資源(特別是CPU)的優先順序。

注:灰色物件不是排程程式物件。


18、作業類

clipboard[50]

? 為其中的成員作業分配一組相同的屬性值

? 是由CREATE_JOB_CLASS過程建立的

? 在作業類中指定作業(使用SET_ATTRIBUTE過程)

? 屬於SYS方案

? 為成員作業設定資源分配

? 將服務屬性設定為所需的資料庫服務名稱

? 將作業分組以區分優先順序

作業類

作業類是參與的成員作業的策略。每個作業類指定一組屬性,例如日誌記錄級別。為作業類分配作業時,作業可以繼承這些屬性。例如,可以指定用相同的策略來清除所有工資單作業的日誌項。

? 可以使用CREATE_JOB_CLASS過程來建立作業類。類始終屬於sys模式。要建立類,必須具有MANAGE SCHEDULER許可權。存在一個名為DEFAULT_JOB_CLASS的預設作業類,此作業類是隨資料庫一起建立的。

? 建立了作業類之後,可以在建立作業時或者在建立作業之後,將作業指定為此作業類的成員,方法是使用DBMS_SCHEDULER程式包中的SET_ATTRIBUTE過程。如果沒有將作業與某個作業類相關聯,則作業屬於該預設作業類。

? 將作業類的服務屬性設定為所需的資料庫服務名稱。這決定了Real Application Clusters環境中執行成員作業的例項和指定給成員作業的系統資源(後者可選)。

? 為成員作業設定資源分配。作業類可以將資料庫資源管理器與排程程式關聯起來,因為每個作業類可以將一個資源使用者組指定為一個屬性。這樣成員作業就屬於指定的使用者組,並根據當前資源計劃中的設定分配資源。此外,還可以將resource_consumer_group屬性保留為NULL並將作業類的服務屬性設定為所需的資料庫服務名稱。然後,該服務可以對映到資源使用者組。如果同時設了resource_consumer_group和服務屬性並且指定的服務對映到資源使用者組,則優先使用resource_consumer_group屬性中指定的資源使用者組。如果建立作業類時未指定資源使用者組,則作業類將對映到DEFAULT_CONSUMER_GROUP資源使用者組。啟用了資源管理器後,對於預設作業類中的作業或者與預設資源使用者組關聯的作業類中的作業,可能無法為其分配足夠的資源以完成各自的任務。

? 為作業分組以區分優先順序。可以為同一作業類中的單個作業分配1到5之間的優先順序值,這樣如果將該類中的兩個作業安排在同一時間啟動,優先順序較高的作業優先。這樣可以確保次要作業不會阻礙重要作業及時完成。如果為兩個作業指定的優先順序值相同,啟動日期較早的作業優先。如果沒有為作業指定優先順序值,則其優先順序預設為3。

例子:建立作業類

clipboard[51]

BEGIN
sys.dbms_scheduler.create_job_class(
logging_level=>DBMS_SCHEDULER.LOGGING_RUNS,
log_history=>10,
resource_consumer_group=>'SYS_GROUP',
service=>'stone',
job_class_name=>'"JOBCLASS1"');
END;


clipboard[52]



19、視窗

clipboard[53]

排程程式視窗:

? 可以在不同時間段啟動作業或更改資源在作業間的分配

? 一次只有一個是活動的

? 是使用CREATE_WINDOW過程建立的

作業的優先順序可以隨時間而變化。例如,在夜間可能要將大部分資料庫資源分配給資料倉儲載入作業,而在白天則將較大一部分資源分配給應用程式作業。要實現這一點,可以使用排程程式視窗來更改資料庫資源計劃。

? 排程程式視窗可以在一天、一週等的不同時間段自動啟動作業或更改資源在作業間的分配。視窗由定義好起始時間和結束時間的時間間隔表示,例如“從凌晨12:00到早上6:00”。

? 在任意給定時間內,只能存在一個有效的視窗。

? 可以使用CREATE_WINDOW過程建立視窗。

排程程式視窗使用作業類來控制資源分配。每個視窗指定了在該視窗開啟(生效)時啟用的資源計劃,而每個作業類指定了資源使用者組或可以對映到使用者組的資料庫服務。因此,在視窗中執行的作業所擁有的資源是根據其作業類的使用者組和視窗的資源計劃分配的(如圖形所示)


20、區分視窗內作業的優先順序

clipboard[54]

區分作業優先順序:

? 在類級別(透過資源計劃)

? 在作業級別(使用作業優先順序屬性)

? 不能擔保不同作業類中的作業的優先順序

在一個資料庫中建立多個作業時,你需要透過某種方式來根據你的業務需求安排作業處理,並指定哪些作業具有最高優先順序。對於特定視窗,可能有多種類別的作業在執行,每一類都具有各自的優先順序。

可以在兩個級別區分優先順序:類級別和作業級別。

? 首先是在類級別區分優先順序,使用的是資源計劃。完全根據類資源分配情況來區分屬於不同類的作業的優先順序。

? 其次是在類內區分優先順序,使用的是作業的作業優先順序屬性。

僅當屬於同一個類的兩個作業同時啟動時,才會考慮優先順序。優先順序較高的作業先啟動。

不能確保不同作業類中的作業按其優先順序執行。例如,APPL_JOBS作業類中的高優先順序作業不一定在ADMIN_JOBS作業類中的低優先順序作業之前啟動,即使它們共享同一個計劃時也是如此。如果APPL_JOBS作業類有較低階別的資源可用,則該類中的高優先順序作業必須等待資源可用,即使在其它作業類中存在可用於低優先順序作業的資源時也是如此。


21、建立一個作業陣列

clipboard[55]

1. 宣告sys.job和sys.job_array型別的變數:

DECLARE

newjob sys.job;

newjobarr sys.job_array;

2. 初始化作業陣列:

BEGIN

newjobarr := SYS.JOB_ARRAY();

3. 調整作業陣列大小以儲存所需的作業數量:

newjobarr.EXTEND(100);

使用作業陣列是一種效率較高的建立作業集的方式。這也適用於輕量作業。在示例中,在一個作業陣列中建立了100 個作業說明,並且將這些說明提交到了單個事務處理的作業佇列中。請注意,對於輕量作業,所需的資訊量非常有限。在此示例中,start_time引數預設為NULL,因此作業被安排為立即啟動。

1.宣告用於儲存作業定義的變數和一個作業陣列變數。

2. 使用SYS.JOB_ARRAY構造器初始化作業陣列。這將為陣列中的每個作業建立一個位置。

3.將陣列大小設定為預期的作業數。

4. 建立每個作業,並將其放入陣列中。在示例中,唯一的差異是作業的名稱。

作業的start_time變數將被省略並預設為NULL,表示將立即執行該作業。

5. 使用CREATE_JOBS過程將陣列中的所有作業作為一個事務處理提交。

注:如果陣列很小,則效能不會顯著優於提交單個作業時的效能。


22、建立一個作業陣列

clipboard[56]

4. 將作業放入作業陣列:

FOR i IN 1..100 LOOP

newjob := SYS.JOB(job_name=> 'LWTJK'||to_char(i),

job_style => 'LIGHTWEIGHT',

job_template => 'MY_PROG',

enabled => TRUE );

newjobarr(i) := newjob;

END LOOP;

5. 將作業陣列作為一個事務處理提交:

DBMS_SCHEDULER.CREATE_JOBS(newjobarr, 'TRANSACTIONAL');

此示例的全部程式碼如下:

DECLARE

newjob sys.job;

newjobarr sys.job_array;

BEGIN

-- Create an array of JOB object types

newjobarr := sys.job_array();

-- Allocate sufficient space in the array

newjobarr.extend(100);

-- Add definitions for jobs

FOR i IN 1..100 LOOP

-- Create a JOB object type

newjob := sys.job(job_name => 'LWTJK' || to_char(i),

job_style => 'LIGHTWEIGHT',   

job_template => 'PROG_1',

enabled => TRUE );

-- Add job to the array

newjobarr(i) := newjob;

END LOOP;

-- Call CREATE_JOBS to create jobs in one transaction

DBMS_SCHEDULER.CREATE_JOBS(newjobarr, 'TRANSACTIONAL');

END;

/


22、建立檔案監視器及基於事件的作業

clipboard[57]

請執行以下任務:

1. 建立排程程式身份證明物件並授予EXECUTE許可權。

2. 建立檔案監視器並授予EXECUTE許可權。

3. 建立其後設資料引數引用事件訊息的排程程式程式物件。

4. 建立引用檔案監視器的基於事件的作業。(可選,使作業能夠針對檔案到達事件的每個例項執行。)

5. 啟用檔案監視器、程式和作業。

建立檔案監視器和基於事件的作業

執行以下任務來建立檔案監視器和在指定檔案到達後啟動的基於事件的作業:

1.建立排程程式身份證明物件(身份證明),用於透過主機作業系統驗證對檔案的訪問許可權,並將對身份證明的EXECUTE許可權授予檔案監視器將啟動的基於事件的作業所屬的模式。

2.建立檔案監視器並將對檔案監視器的EXECUTE許可權授予引用檔案監視器的基於事件的作業所屬的任何模式。

3.建立其後設資料引數引用事件訊息的排程程式程式物件。

- 使用EVENT_MESSAGE屬性定義後設資料引數。

- 建立具有一個型別為SYS.SCHEDULER_FILEWATCHER_RESULT的引數的儲存過程,供該程式呼叫。儲存過程必須具有一個SYS.SCHEDULER_FILEWATCHER_RESULT型別(事件訊息的資料型別)的引數。該引數的位置必須與所定義的後設資料引數的位置相匹配。該過程可以訪問此抽象資料型別的屬性,以瞭解有關已到達檔案的資訊。

4.建立引用檔案監視器的基於事件的作業。可以使用DBMS_SCHEDULER.SET_ATTRIBUTE過程使作業能夠針對檔案到達事件的每個例項執行,即使該作業已經在處理之前的一個事件。將PARALLEL_INSTANCES屬性設定為TRUE。

BEGIN

DBMS_SCHEDULER.SET_ATTRIBUTE('','PARALLEL_INSTANCES', TRUE);

END;

這樣作業將作為輕量作業執行,因此可以快速啟動作業的多個例項。如果將PARALLEL_INSTANCES設定為預設值FALSE,則當基於事件的作業已經在處理

一個事件時,此時出現的檔案監視器事件將被丟棄。

5.啟用檔案監視器、程式和作業。


23、從遠端系統啟用檔案到達事件

clipboard[58]

執行以下任務在遠端系統上啟用檔案到達事件觸發功能:

1. 設定資料庫以執行遠端外部作業。

2. 在第一個遠端系統上安裝、配置、註冊並啟動排程程式代理。

3. 為其餘的每個遠端系統重複步驟2。

要接收來自遠端系統的檔案到達事件,你必須在系統上安裝排程程式代理,且必須在資料庫中註冊代理。該遠端系統不需要Oracle資料庫例項來生成檔案到達事件。


24、排程遠端資料庫作業

clipboard[59]

? 建立一個作業在同一主機或遠端主機上的另一個資料庫例項上執行儲存過程和匿名PL/SQL塊。

? 目標資料庫可以是任何版本的Oracle資料庫。

? DBMS_SCHEDULER.CREATE_DATABASE_DESTINATION和DBMS_SCHEDULER.CREATE_CREDENTIAL可以用於遠端資料庫作業。

? 作業型別為PLSQL_BLOCK和STORED_PROCEDURE的作業可以是SET_ATTRIBUTE為DESTINATION和CREDENTIAL屬性呼叫的目標。

現在,可以建立一個作業在同一主機或遠端主機上的另一個資料庫例項上執行儲存過程和匿名PL/SQL塊。目標資料庫可以是任何版本的Oracle資料庫。

現在沒有用於支援遠端資料庫作業的新過程,但是對現有DBMS_SCHEDULER過程進行了更改以支援該功能。以下提供了詳細資訊。


25、建立遠端資料庫作業

clipboard[60]

執行以下任務以建立遠端作業:

1. 設定遠端作業的發起資料庫。

2. 使用DBMS_SCHEDULER.CREATE_JOB建立作業。

3. 使用DBMS_SCHEDULER.CREATE_CREDENTIAL建立身份證明。

4. 使用DBMS_SCHEDULER.SET_ATTRIBUTE設定作業CREDENTIAL_NAME。

5. 使用DBMS_SCHEDULER.SET ATTRIBUTE設定作業的DESTINATION屬性。

6. 使用DBMS_SCHEDULER.ENABLE啟用作業。

建立遠端資料庫作業

你可以執行示例中列出的任務來建立遠端資料庫作業。

要設定遠端作業的發起資料庫,請執行以下步驟:

1. 驗證是否已安裝XML DB。

2. 啟用至資料庫的HTTP連線。

BEGIN

DBMS_XDB.SETHTTPPORT(port);

END;

3. 執行prvtrsch.plb指令碼。

4. 設定排程程式代理的註冊口令。

BEGIN

DBMS_SCHEDULER.SET_AGENT_REGISTRATION_PASS('password');

END;


26、排程多個目標作業

clipboard[61]

? 該功能可用於指定要在其上執行作業的多個目標。

? 它使使用者能夠從建立作業的資料庫監視和控制這些作業。

? 多目標作業執行時,可將其視為一個作業集合,其中的各個作業是彼此近似相同的副本。

? 所有作業都將基於在作業開始日期中指定的時區執行,或將使用源資料庫的時區。

多目標作業功能允許你指定多個要在其上執行作業的目標。你可以從建立作業的資料庫監視和控制這些作業。其中包括以下功能:

? 指定必須在其上執行作業的數個資料庫或計算機

? 將在多個目標上排程的同一作業作為單個實體進行修改

? 停止或刪除在一個或多個遠端目標上執行的作業

? 檢視作業例項在所有作業目標上的狀態

請注意,在該功能的初始版本中,所有目標都基於在作業開始日期中指定的時區執行,或預設使用源資料庫的時區。


27、檢視排程器後設資料

clipboard[62]

主要排程程式管理檢視,顯示:

? *_SCHEDULER_JOBS:所有作業,包括啟用的和禁用的

? *_SCHEDULER_SCHEDULES:所有排程

? *_SCHEDULER_PROGRAMS:所有程式

? *_SCHEDULER_RUNNING_JOBS:活動的作業狀態

? *_SCHEDULER_JOB_LOG:所有作業狀態更改

? *_SCHEDULER_JOB_RUN_DETAILS:所有已完成的作業執行

SELECT job_name, status, error#, run_duration

FROM USER_SCHEDULER_JOB_RUN_DETAILS;

JOB_NAME STATUS ERROR# RUN_DURATION

---------------- ------ ------ ------------

GATHER_STATS_JOB SUCCESS 0 +000 00:08:20

PART_EXCHANGE_JOB FAILURE 6576 +000 00:00:00

檢視排程程式後設資料

作業表是一個包含所有作業的容器,每個資料庫有一個作業表。作業表用於儲存所有作業的資訊,例如所有者名稱和日誌記錄級別。可以在*_SCHEDULER_JOBS檢視中檢視這些資訊。

作業是資料庫物件,因此可能會累積起來並佔用過多的空間。為避免發生這種情況,預設情況下會在作業完成後自動刪除作業物件。該行為由auto_drop作業屬性控制。

DBA 和授權使用者可以透過多個檢視檢視與排程程式、作業、排程和視窗等有關的重要操作資訊。這些檢視包括:

? *_SCHEDULER_PROGRAM_ARGS:顯示為所有程式定義的所有引數及預設值(如果存在)

? *_SCHEDULER_JOBS:顯示所有的作業,不管是已啟用還是禁用的作業

? *_SCHEDULER_JOB_RUN_DETAILS顯示所有已完成(失敗或成功)的作業執行。

每個作業例項都有對應的一行。每一行中都包含有關該例項的作業執行情況的資訊。

ERROR# 是遇到的第一個錯誤的編號

? *_SCHEDULER_GLOBAL_ATTRIBUTE:顯示排程程式屬性的當前值

? *_SCHEDULER_JOB_ARGS:顯示所有作業的所有已設定的引數值

? *_SCHEDULER_JOB_CLASSES:顯示所有作業類

對於作業鏈:

? *_SCHEDULER_RUNNING_CHAINS:顯示所有活動鏈

? *_SCHEDULER_CHAIN_STEPS:顯示所有鏈的所有步驟

? *_SCHEDULER_CHAINS:顯示所有鏈

? *_SCHEDULER_CHAIN_RULES:顯示所有鏈的所有規則

對於其它高階物件視窗:

? *_SCHEDULER_WINDOWS顯示所有視窗

? *_SCHEDULER_WINDOW_GROUPS顯示所有視窗組

? *_SCHEDULER_WINGROUP_MEMBERS顯示所有視窗組的成員,一行對應一個組成員

? *_SCHEDULER_JOB_LOG顯示作業的所有狀態更改

? *_SCHEDULER_CREDENTIALS顯示資料庫中的身份證明的列表,其中密碼進行了模糊處理

? *_SCHEDULER_JOB_ROLES按資料庫角色顯示所有作業

輕量作業與常規作業是透過相同的檢視檢視的:

? *_SCHEDULER_JOBS:顯示所有作業,包括JOB_STYLE=‘LIGHTWEIGHT’的作業

? *_SCHEDULER_JOB_ARGS:還顯示輕量作業的所有已設定的引數值

? 因為輕量作業不是資料庫物件,所以無法透過*_OBJECTS檢視檢視輕量作業

從Oracle Database 11gR2 開始:

? *_SCHEDULER_NOTIFICATIONS顯示已經設定的電子郵件通知

? *_SCHEDULER_FILE_WATCHERS顯示檔案監視器的配置資訊

以下檢視顯示與多目標作業有關的資訊:

? *_SCHEDULER_DESTS:顯示可在其上排程遠端作業的所有目標。該檢視包含外部

目標(對於遠端外部作業)和資料庫目標(對於遠端資料庫作業)

? *_SCHEDULER_EXTERNAL_DESTS:顯示所有已在資料庫中註冊且可用作遠端外部作業目標的代理

? *_SCHEDULER_DB_DESTS:顯示您可在其上排程遠端資料庫作業的所有資料庫

? *_SCHEDULER_GROUPS:顯示您的方案中的組或資料庫中的所有組

? *_SCHEDULER_GROUP_MEMBERS:顯示您的方案中的組成員或資料庫中的所有組成員

? *_SCHEDULER_JOB_DESTS:顯示遠端資料庫中的作業的狀態

注:在上面列出的檢視中,檢視名稱開頭的星號會被替換為DBA、ALL或USER。

參考:http://blog.csdn.net/rlhua/article/details/13355531

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28536251/viewspace-2137270/,如需轉載,請註明出處,否則將追究法律責任。

相關文章