懵懂oracle之存儲過程3--JOB詳解

来源:http://www.cnblogs.com/snowballed/archive/2017/07/29/7245739.html
-Advertisement-
Play Games

oracle存儲過程開發相關知識彙總:此篇主要介紹和存儲過程有密切關係的Oracle JOB的方方面面,包括有它的初始化許可權、初始化參數job_queue_processes、dbms_job系統包內部參數及存儲過程的詳解分析和調用範例來增刪改查JOB、JOB涉及的表和視圖的分析、JOB的失敗重試以... ...


      在前面學習了存儲過程的開發、調試之後,我們現在就需要來使用存儲過程了。簡單的使用,像上篇《懵懂oracle之存儲過程2》中提到的存儲過程調用,我們可以將寫好的存儲過程在另一個PL/SQL塊亦或是另一個存儲過程中調用執行,而很多情況下,我們往往需要定時執行這個存儲過程,那麼我們就需要使用到Oracle的JOB,讓我們的資料庫可以定期的執行特定的任務。

      下麵就讓我們來瞭解下JOB的方方面面:

      在Oracle 10g以前,Oracle提供了dbms_job系統包來實現job,到Oracle 10g時,就多出了dbms_scheduler包來實現job,它比dbms_job擁有更強大的功能和更靈活的機制,在本文暫只介紹dbms_job的知識,所用的資料庫版本Oracle 11g

      1 初始化

      1.1 初始化許可權

      使用dbms_job包如果遇到許可權問題,那麼需要使用管理員賬號給此用戶賦予許可權:

1 grant execute on dbms_job to 用戶;

      1.2 初始化參數

      重點關註job_queue_processes參數,它告訴了資料庫最多可創建多少個job進程來運行job,可通過下麵語句查詢改參數值情況:

1 select name, value, display_value from v$parameter where name in ('spfile', 'job_queue_processes');

      當job_queue_processes參數對應的value為0時,則代表所有創建的job都不會運行,因此我們需將此參數值根據各自需要修改至n(1~1000):

  • 當上述語句未查詢出spfile參數時,則表示資料庫以pfile啟動,該文件預設位置為%ORACLE_HOME%\database目錄下的init<sid>.ora文件(sid-->資料庫實例名)。此時若要修改參數值,則需打開此文件進行增加或修改下行信息,而後重啟資料庫才能生效:
    1 JOB_QUEUE_PROCESSES=n
  • 當上述語句可查詢出spfile參數時,則表示資料庫以spfile啟動,該文件的位置可從value值中得到。此時若要修改參數值,則可通過在資料庫執行下列語句進行修改:

    1 alter system set job_queue_processes=n;
    2 /*
    3    alter system 參數名=值 [scope=應用範圍];
    4    scope需知:
    5        scope=both,表示修改會立即生效且會修改spfile文件以確保資料庫在重啟後也會生效如果(以spfile啟動此項為預設值);
    6        scope=memory,表示修改會立即生效但不會修改spfile文件,因此重啟後失效(以pfile啟動此項為預設值,且只可設置這個值);
    7        scope=spfile,表示只修改spfile文件,在重啟資料庫後才生效(對應靜態參數則只可設置此項值,設置其它值會報錯:
    8                                          ORA-02095: specified initialization parameter cannot be modified)。
    9 */

      2 dbms_job包分析(可在資料庫中查看此包獲取相關信息,暫未分析包內user_export存過的用法)

      2.1 內部存過參數彙總

      2.2 內部存過詳解

 1 create or replace procedure sp_test_hll_170726 AUTHID CURRENT_USER as
 2   v_flag number;
 3 begin
 4   select count(1)
 5     into v_flag
 6     from user_tables
 7    where table_name = 'TEST_TABLE_170726';
 8   if v_flag = 0 then
 9     execute immediate 'create table test_table_170726(id number, create_time date default sysdate)';
10   end if;
11   select count(1)
12     into v_flag
13     from user_sequences
14    where sequence_name = 'SEQ_TEST_TABLE_170726_ID';
15   if v_flag = 0 then
16     execute immediate 'create sequence seq_test_table_170726_id';
17   end if;
18   execute immediate 'insert into test_table_170726(id) values(seq_test_table_170726_id.nextval)';
19   commit;
20 end sp_test_hll_170726;
21 /
新建存過sp_test_hll_170726以作後面測試使用

1) submit:用於新建一個定時任務

  • 定義:
    1 procedure submit(job       out binary_integer,
    2                  what      in varchar2,
    3                  next_date in date default sysdate,
    4                  interval  in varchar2 default 'null',
    5                  no_parse  in boolean default false,
    6                  instance  in binary_integer default 0,
    7                  force     in boolean default false);
  • 範例1:
     1 declare
     2   jobno number;
     3 begin
     4   dbms_job.submit(
     5                  jobno,--定義的變數作為submit存過的出參,submit內部調用序列生成此值
     6                  'sp_test_hll_170726;' , --job要執行的工作(範例為要執行的存儲過程,必須加分號,格式如:存過1;存過2;存過3;……)
     7                   sysdate,--設置下次運行時間為當前系統時間,以使job在提交後立馬運行(因為之後的系統時間>=此時的'sysdate')
     8                  'sysdate+10/(24*60*60)' --設置定時周期為10秒運行一次
     9                  );
    10   dbms_output.put_line(jobno);--輸出以供查看本次創建的job的編號,或查看dba_jobs/all_jobs/user_jobs視圖中最新行亦可
    11   commit;--請記得提交,提交之後才會生效並按計劃執行此項定時任務
    12 end;
    13 /
  • 範例2(存過sp_hll_test_20170415見《懵懂oracle之存儲過程》):
     1 declare 
     2   jobno number; 
     3 begin 
     4   dbms_job.submit(jobno,
     5   'declare
     6       a      number;
     7       b      date;
     8       c      varchar2(20);
     9       d      number;
    10       status user_tables.status%type;
    11       e      varchar2(200);
    12     begin
    13       sp_hll_test_20170415(a, b, c, d, status, e);
    14       a := 3;
    15       sp_hll_test_20170415(a, to_date(''2017-6-16'', ''yyyy-mm-dd''), ''我是常量C'', d, ''0'', e);
    16       insert into test_table_170726(id,create_time) values (seq_test_table_170726_id.nextval,to_date(''2017-6-16'', ''yyyy-mm-dd''));
    17       commit;
    18     end;', --job要執行的工作(範例為要執行的PL/SQL塊,塊內單引號處理成雙單引號)
    19     case
    20          when sysdate > trunc(sysdate) +
    21               (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60) then
    22           trunc(sysdate + 1) +
    23           (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60)
    24          else
    25           trunc(sysdate) + (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60)
    26        end, --設置下次運行時間為接下來最近的一次11點11分11秒
    27     null --設置為單次運行,一般用於需單次運轉的耗時較長的任務,在成功完成後job記錄會自動刪除掉
    28   ); 
    29   dbms_output.put_line(jobno);
    30   commit;
    31 end;
    32 /
  • 備註:
    1. what參數,用於定時任務執行的具體內容:
                格式  ==>  存過1;存過2;存過3;……  |    '處理過單引號的PL/SQL塊'
        建議使用後者,如果是前者情況,也用begin end進行包裹,如 begin 存過1;存過2;存過3;…… end; ,否則少數情況下會出現一些莫名其妙的問題……暫無實例。
    2. interval參數,用於設置定時任務時間間隔:
                格式  ==>  null  |  '處理過單引號的時間表達式'
        設置為null表示單次運行,在成功完成後會從JOB任務隊列中刪除此JOB。
        時間表達式:通過 select 時間表達式 from dual; 可得到一個未來時間點,每次任務開始執行之前都獲取這個未來時間點作為下次運行任務的時間,然後在任務執行完成後,才會把此時間更新至JOB任務隊列的next_date欄位中,等待下次sysdate >= next_date時再次執行此任務。之所以“>=”而不是“=”,是因為存在後面幾種情況:
            -1-創建定時任務時,next_date就小於系統時間;
            -2-單次任務執行的時間超過任務開始執行時計算出的next_date,以致next_date小於任務執行完成後的系統時間,此時任務會立馬進行再一輪的執行;
            -3-參數job_queue_processes的限制或者資料庫性能的限制或資料庫關閉等,導致next_date=當時的sysdate時,任務無法按時開始執行。
        由於上面第三種情況的存在,因此對於interval參數設置大致可分兩種情況:
            -1 時間定隔迴圈,不考慮時間點的精確性,則只需使用sysdate即可,例如 interval = 'sysdate + 數值' ,數值(1=1天,1/24=1小時,1/(24*60)=1分鐘,1/(24*60*60)=1秒鐘),數值為1時實現每隔一天執行一次這樣的簡單迴圈。
            -2 時間定點迴圈,需確保每次執行的時間點精確性,則一般需配合trunc函數進行處理,例如 interval = 'trunc(sysdate,''dd'') + 數值' ,數值為1/24時實現每天1點執行此任務這樣精確的迴圈,以消除每次執行定時任務時的時間飄移的積累,以致時間點越來越不正確,同時由他人手工調用dbms_job.run對某定時任務進行手動執行,導致取手動運行任務時的系統時間作為sysdate計算下次的時間會產生更大的時間差異,也會使執行的時間和當初計劃的時間不符的現象出現,因此用trunc等函數處理來保證時間點的精確性。
        常用函數trunc、numtoyminterval、numtoyminterval、add_months、next_day、last_day介紹:
     1 select sysdate, trunc(sysdate), trunc(sysdate,'MON') from dual;
     2 /*
     3     trunc(date, [format]):
     4     format可取值彙總(不區分大小寫):
     5     本世紀第一天 ==> CC,SCC
     6     本年第一天 ==> SYYYY, YYYY, YEAR, SYEAR, YYY, YY, Y
     7     本ISO年第一天(每個星期從星期一開始,每年的第一個星期包含當年的第一個星期四(並且總是包含1月4日)) ==> IYYY, IY, I
     8     本季度第一天 ==> Q
     9     本月第一天 ==> MONTH, MON, MM, RM
    10     本周第一天 ==> WW(按年度1月1日的第一天為每周第一天),
    11                                IW(星期一為每周第一天),
    12                                W(按月份1日的第一天作為每周第一天),
    13                                DAY, DY, D(星期日為每周第一天)
    14     本日(零點零分)(預設值) ==> DDD, DD, J
    15     本小時(零分零秒) ==> HH, HH12, HH24
    16     本分鐘(零秒) ==> MI
    17 */
    18 
    19 select sysdate + numtoyminterval(-5, 'year') 五年前,
    20        sysdate + numtodsinterval(-10, 'day') 十天前,
    21        sysdate + numtodsinterval(-2, 'hour') 兩小時前,
    22        sysdate + numtodsinterval(1, 'minute') 一分鐘前,
    23        sysdate + numtodsinterval(10, 'second') 十秒後,
    24        sysdate + numtoyminterval(3, 'month') 三月後
    25   from dual;
    26 /*
    27   numtodsinterval(num, format):
    28   num可取整數(正整數表示加,負整數表示減);
    29   format可取值彙總(不區分大小寫):DAY,HOUR,MINUTE,SECOND
    30  
    31   numtoyminterval(num, format):
    32   num可取整數(正整數表示加,負整數表示減);
    33   format可取值彙總(不區分大小寫):YEAR,MONTH
    34 */
    35 
    36 select sysdate 現在, add_months(sysdate, -12) 一年前, add_months(sysdate, 3) 三月後 from dual;
    37 /*
    38   add_months(date, num):
    39   date為具體時間,經add_months處理不會變動時分秒,日期年月進行加減;
    40   num可取整數(正整數表示加,負整數表示減);
    41 */
    42 
    43 select next_day(sysdate,
    44                 case value
    45                   when 'SIMPLIFIED CHINESE' then
    46                    '星期六'
    47                   else
    48                    'SAT'
    49                 end) 下周一此時此分此秒, next_day(sysdate, 1) 下周日此時此分此秒
    50   from v$parameter
    51  where name = 'nls_date_language';
    52 /*
    53     next_day(date, format) :
    54     date為具體時間,經next_day處理不會變動時分秒,日期被處理至下個周一~周日;
    55     format可取值彙總(不區分大小寫):
    56         星期一~星期日(對應字元集NLS_DATE_LANGUAGE = SIMPLIFIED CHINESE)
    57         Monday~Sunday 或者 Mon~Sun(對應字元集NLS_DATE_LANGUAGE = AMERICAN)
    58         1~7(1為周日)
    59 */
    60 
    61 select to_date('2017-2-1 11:11:11', 'yyyy-mm-dd hh24:mi:ss') "2017/2/1 11:11:11",
    62        last_day(to_date('2017-2-1 11:11:11', 'yyyy-mm-dd hh24:mi:ss')) "17年2月末此時此分此秒"
    63   from dual;
    64 /*
    65     last_day(date) :
    66     date為具體時間,經last_day處理不會變動時分秒,日期被處理至月底最後一天
    67 */
    3. instance、force參數,用於設置定時任務於資料庫實例的關聯性:
          在Oracle RAC環境下,多個資料庫實例併發使用同一個資料庫,是Oracle9i新版資料庫中採用的一項新技術,解決了傳統資料庫應用中面臨的一個重要問題:高性能、高可伸縮性與低價格之間的矛盾!但是在涉及到我們的定時任務時,如果是RAC環境,它是怎麼運行的呢?有多台機器這個定時任務這次到底會在哪個機器上運行呢?instance參數就可配置指定機器對應的資料庫實例,如不修改預設此值為0,表示就是所有資料庫實例都可運行此項定時任務,每次這個任務執行時就可能在a機器,也可能在b機器,一般我們也是不指定此值的。當遇到需要指定此值時,需關註下麵查詢的情況,取instance_name作為instance參數值。
    1 select inst_id,instance_number,instance_name,host_name,
    2   utl_inaddr.get_host_address(host_name) public_ip,status,version
    3 from gv$instance;

          同時force參數在設置為true時,也能達到和instance=0時一樣的效果,解除JOB執行和資料庫實例的關聯性,它的預設值是false,表示按照instance值的情況進行判斷資料庫實例的關聯性。

    4. what、interval參數都需註意內部單引號處理成雙單引號,可用 select 參數值 from dual; 查詢得到實際對應的存過或PL/SQL塊或時間表達式,來判斷是否設置正確。

2) isubmit:用於新建一個定時任務同時指定JOB編號

  • 定義:
    1 procedure isubmit(job       in binary_integer,
    2                   what      in varchar2,
    3                   next_date in date,
    4                   interval  in varchar2 default 'null',
    5                   no_parse  in boolean default false);
  • 範例:
     1 begin 
     2   dbms_job.isubmit(23, --指定job編號,不可用已有job的編號,否則報違反唯一約束的異常
     3   'declare
     4       a      number;
     5       b      date;
     6       c      varchar2(20);
     7       d      number;
     8       status user_tables.status%type;
     9       e      varchar2(200);
    10     begin
    11       sp_hll_test_20170415(a, b, c, d, status, e);
    12       a := 3;
    13       sp_hll_test_20170415(a, to_date(''2017-6-16'', ''yyyy-mm-dd''), ''我是常量C'', d, ''0'', e);
    14       insert into test_table_170726(id,create_time) values (seq_test_table_170726_id.nextval,to_date(''2017-6-16'', ''yyyy-mm-dd''));
    15       commit;
    16     end;',
    17     sysdate,
    18     'trunc(sysdate + numtoyminterval(1,''year''),''yyyy'')+1/24' --每年一月一號一點執行
    19   );
    20   commit;
    21 end;
    22 /
  • 備註:
    除job為入參需指定外,其它使用情況與submit相同,指定job編號時,不可用已存在job的編號,否則導致異常 ORA-00001: 違反唯一約束條件 (SYS.I_JOB_JOB) 。

3) remove:用於從JOB任務隊列中移除一個JOB(不會中斷仍在運行的JOB)

  • 定義:
    1 procedure remove(job in binary_integer);
  • 範例:
    1 begin
    2   dbms_job.remove(23);
    3   commit;
    4 end;
    5 /
  • 備註:
    移除需移除已存在JOB,否則導致異常 ORA-23421: 作業編號111在作業隊列中不是一個作業 。

4) what:用於修改what參數值

  • 定義:
    1 procedure what(job in binary_integer, what in varchar2);
  • 範例:
    1 declare
    2   jobno number;
    3 begin
    4   select job into jobno from user_jobs where what like '%sp_test_hll_170726%';
    5   dbms_job.what(jobno,  'begin sp_test_hll_170726; end;'); --修改成pl/sql塊形式
    6   commit;
    7 end;
    8 /

5) next_date:用於修改next_date參數值

  • 定義:
    1 procedure next_date(job in binary_integer, next_date in date);
  • 範例:
    1 declare
    2   jobno number;
    3 begin
    4   select job into jobno from user_jobs where what like '%sp_test_hll_170726%';
    5   dbms_job.next_date(jobno,  trunc(sysdate + 1)); --修改最近一次待執行的時間至明天凌晨
    6   commit;
    7 end;
    8 /

6) interval:用於修改interval參數值

  • 定義:
    1 procedure interval(job in binary_integer, interval in varchar2);
  • 範例:
    1 declare
    2   jobno number;
    3 begin
    4   select job into jobno from user_jobs where what like '%sp_test_hll_170726%';
    5   dbms_job.interval(jobno, 'sysdate + 1'); --修改為每隔一天運行一次
    6   commit;
    7 end;
    8 /

7) instance:用於修改instance、force參數值

  • 定義:
    1 procedure instance(job      in binary_integer,
    2                    instance in binary_integer,
    3                    force    in boolean default false);
  • 範例:
    1 declare
    2   jobno number;
    3 begin
    4   select job into jobno from user_jobs where what like '%sp_test_hll_170726%';
    5   dbms_job.instance(jobno, 1); --修改為資料庫實例1才能運行此定時任務
    6   commit;
    7 end;
    8 /
  • 備註:
        請勿修改已在運行的JOB的資料庫實例,根據網路搜索得知:job會不再運行,並出現等待事件:enq: TX - row lock contention,執行的sql是 update sys.job$ set this_date=:1 where job=:2 ,也就是在更新sys的sys.job$表,最後只能殺掉此會話,才消除此等待事件。
        一般情況下,建立不要指定JOB在特定實例運行,通常都預設為0。
        下麵change也需註意此處備註。

8) change:用於修改what、next_date、interval、instance、force參數值

  • 定義:
    1 procedure change(job       in binary_integer,
    2                  what      in varchar2,
    3                  next_date in date,
    4                  interval  in varchar2,
    5                  instance  in binary_integer default null,
    6                  force     in boolean default false);
  • 範例:
     1 declare
     2   jobno number;
     3 begin
     4   select job into jobno from user_jobs where what like '%sp_test_hll_170726%';
     5   dbms_job.change(jobno, 
     6         'begin sp_test_hll_170726; end;',
     7         sysdate,
     8         'sysdate + 1/24');--實現多參數修改
     9   commit;
    10 end;
    11 /

9) broken:用於給定時任務添加或去除中斷標識,將任務掛起或取消掛起(不會中斷仍在運行的JOB)

  • 定義:
    1 procedure broken(job       in binary_integer,
    2                  broken    in boolean,
    3                  next_date in date default sysdate);
  • 範例:
    1 	   
    
    
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.截取方法 截取字元串的abcdefg中的efg. 註意:str.length從1的開始數 var str="abcdefg"; (1).slice() : console.log(str.slice(4,7)); //efg第一個參數開始,第二個參數結束並且取不到.遇到負數把length和負數相 ...
  • 被遺棄的標簽和屬性 <center> 定義居中的文本 -> text-align <font>和<basefont> 定義HTML字體 -> font-family字體系列 font-size字體尺寸 <s>和<strike> 定義刪除線文本 <u> 定義下劃線文本 bgcolor 定義背景顏色 - ...
  • logcat 一、簡介 非常好用的日誌工具 二、常見操作 1、選擇對應級別的日誌 2、添加日誌過濾器filter 三、代碼實例 建立日誌filter 下麵代碼運行的日誌結果 com.fry.logcatTest.MainActivity ...
  • URI
    URI 一、介紹 ...
  • intent Filter 一、介紹 如果一個 Intent 請求在一片數據上執行一個動作, Android 如何知道哪個應用程式(和組件)能用來響應這個請求呢? Intent Filter就是 用來註冊 Activity 、 Service 和 Broadcast Receiver 具有能在某種數 ...
  • 有 App 源碼時,可以直接查看 AndroidManifest.xml 文件。 " xmlns:android="http://schemas.android.com/apk/res/android"> 只有 apk 安裝包時,可以通過 Android SDK 中的aapt(build-tools... ...
  • 隱式intent 一、隱式意圖介紹 顯式意圖我們前面已經提到,形如: Intent intent = new Intent(); intent.setClass(this,Other.class); //此句表示顯式意圖,因為明確設置激活對象為Other類 startActivity(intent) ...
  • 許可權是執行特殊SQL語句的權利。資料庫管理員 (DBA) 是一個具有授予用戶訪問資料庫及其對象的能力的高級用戶。用戶需要系統許可權來訪問資料庫,需要對象許可權來操縱資料庫中對象的內容。用戶也可以將被授予的許可權給其它用戶或者角色,角色是相關許可權的命名分組。方案是對象的集合,例如,視圖和序列的集合。方案被數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...