salesforce 零基礎開發入門學習(五)異步進程介紹與數據批處理Batchable

本篇知識參考:https://developer.salesforce.com/trailhead/force_com_dev_intermediate/asynchronous_apex/async_apex_batchjava

salesforce對於數據操縱個數以及次數有嚴格的限制,超過限制值則拋出異常。sql

salesforce對於不少數據操縱的次數均有嚴格的限制。具體限制以下:異步

Number of SOQL queries: 100                             -->一次執行SOQL的次數不能超過100次
Number of query rows: 50000                             -->一次查出的數據行數不能超過50000條
Number of SOSL queries: 20                               -->一次執行SOSL次數不能超過20次
Number of DML statements: 150                         -->DML語句不能超過150條
Number of DML rows: 10000                               -->一次操做數據行數不能超過10000行
Maximum CPU time: 10000                                 -->最大的CPU時間不能超過10000ms
Maximum heap size: 6000000                             -->堆大小不能超過6000000B
Number of callouts:100                                       -->一次執行callouts次數不能超過100次
Number of Email Invocations: 10                          -->Email調用次數不能超過10次
Number of future calls: 50                                   -->調用Future次數不能超過50次
Number of queueable jobs added to the queue:50  -->添加到隊列的queueable job數量不能超過50次
Number of Mobile Apex push calls: 10                   -->移動端Apex push調用最多不能超過10次async

由於對於DML操做有限制,好比由於項目需求,須要修改50萬條數據,直接調用Database.update()便會拋出異常,由於salesforce只容許一次性查出5萬條數據而且只容許一次性修改1萬條數據。若是須要達到目的,就只能使用批處理。ide

一)數據批處理Batchable測試

數據批處理適用於批量處理成百上千萬的數據。批處理採用異步的處理方式處理數據,最多能夠處理5000萬條數據。新建一個批處理類須要實現Database.Batchable接口。此接口封裝了三個方法,而且三個方法構成一個批處理的生命週期。start()方法用於查詢數據,並將查詢數據封裝到List中;execute()方法用於操做數據,形參中List爲start()方法中返回的數據,能夠直接對此List進行修改以達到批處理行爲。批處理所有執行後執行finish()方法,finish()方法用於進行一些後期處理,好比發郵件等操做。this

須要注意的是:spa

1.start()方法執行後,數據便沒法修改;線程

2.execute()原則上能夠執行屢次,好比在調用的時規定執行次數,則按照規定次數執行execute();debug

3.finish()方法執行之後,批處理類用到的全部的變量對象都會恢復到最開始的狀態,即值回滾到最開始狀態;

4.若是批處理類不實現Database.Stateful接口,則變量只在相應方法起做用,當方法執行完成,變量則會回滾到初始狀態。

eg:在類中聲明成員變量A,在start()方法對A進行處理,若是類不實現上述接口,則方法執行完start()方法後A會回滾到初始狀態,在execute()方法或者finish()方法調用A時值爲最開始聲明的值,在start方法的處理結果不保留。

實現批處理類步驟明確,只須要執行如下的步驟:

1.實現Database.Batchable接口;

2.實現start()方法,此方法中一般寫查詢語句,並將數據經過Database.getQueryLocator(queryString)方法將數據傳遞到execute()形參中。此方法定義:

global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {} ;

3.實現execute()方法,此方法對數據進行DML操做。此方法定義:global void execute(Database.BatchableContext BC, list<P>){} ;

4.實現finish方法(),此方法進行後期處理,若是無須要處理,能夠不進行處理。

上面步驟提到了Database.BatchableContext接口,此接口用於追蹤批處理的進展。經過此接口能夠獲取相關的jobId,詳情請參看官方文檔。

 

下面舉個例子,建立一個商品表GOODS__c,裏面含有一個字段爲價格GoodsPrice__c。如今須要將原來數據的GoodsPrice__c加1,代碼以下:

 1 global with sharing class GoodsBatch implements Database.Batchable<sObject>,Database.Stateful{
 2     Integer queryCount = 0;
 3     
 4     String myEmailAddress = 'myAddress@xx.com';
 5     
 6     global Database.QueryLocator start(database.BatchableContext bc )
 7     {
 8         String query = 'select GOODSPRICE__c,Id from GOODS__c';
 9         return Database.getQueryLocator(query);
10     }
11     
12     global void execute (Database.BatchableContext bc, List<GOODS__c> goodsList)
13     {
14         for(GOODS__c goods : goodsList) {
15             Decimal price = goods.GoodsPrice__c;
16             price += 1;
17             queryCount +=1;
18         }
19         upsert goodsList;
20     }
21     
22     global void finish(Database.BatchableContext bc)
23     {
24         /*--------execute finish----------*/
25         /*注意:若是不實現Database.Stateful接口,則queryCount爲0
26               由於在execute執行完成便會回滾到初始狀態*/
27         System.debug('query count:' + queryCount);
28         //send email
29         Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
30         email.setToAddresses(new String[]{myEmailAddress});//set mail getter
31         email.setSubject('show count'); //set subject
32         email.setHtmlBody('query Count' + queryCount);
33         Messaging.sendEmail(new Messaging.SingleEmailMessage[] { email });
34     }
35 }
36 
37 implements Batchable
implements Batchable

 二)異步進程簡單介紹

異步進程用於在單獨的線程內來運行進程。異步進程是一個在後臺運行,不須要用戶等到任務結束的進程或者方法。異步進程好處不少,包括不須要用戶等待,節省響應時間等等。

異步進程主要有如下幾種形式:

異步進程
類型 介紹 經常使用情景
Future方法 在本身線程中運行,直到資源可用才運行 Web service callout.
Batch Apex 運行大量的Job,數量超過正常處理限制 數據DML操做
QueueableApex 和Future相似,可是提供額外的工做鏈,容許完成更復雜的類型 執行順序處理操做與外部Web服務。
ScheduledApex 指定時間運行apex 固定時間的任務,例如每日或每週等任務
  • Future方法

   Future方法用於異步處理,經常使用於Web service callout操做.Future方法須要有幾個規範:

    1.方法必須是靜態static的;

  2.方法上方須要使用@Future標籤;

  3.方法返回類型必須是void類型;

  4.方法參數必須是模塊私有的變量,不能使public等;

  5.方法參數不容許使用標準的Object或sObject類型,可使用基本類型或者集合類型;

  6.不能再一個future方法調用另外一個future方法,當future方法運行的時候也不能夠在trigger中調用;

  7.future方法中不能使用getContent()和getContentAsPDF()方法。

  如下爲Future方法代碼舉例。此方法用來輸出符合Id在形參List中的全部Account的Id。 

public with sharing class FutureSample {
    @future
    public static void futuremethod(List<ID> ids) {
    	String sql = 'select Id,Name from Account where Id in :ids';
    	List<Account> accounts = Database.query(sql);
    	for(Account account : accounts) {
    		System.debug(account.Id);
    	}
    }
} 

  有幾點須要注意:

  1)future方法執行不保證質量,若是須要好的質量可使用Queueable方法;

  2)能夠容許兩個future方法同時運行,當兩個future方法同時對一條記錄進行操做時,可能引發記錄鎖定或者運行時異常。

  總之,使用future方式不保證質量。。。。。。並且有不少限制,開發的時候能不用就不用,若是必須使用狀況下本身評估一下。

      測試future方法在Test類中執行,和普通的方法測試區別的是,future方法執行須要在Test.startTest()和Test.stopTest()方法中進行.如下爲測試代碼:

@isTest
private class Test_FutureSample {
    static testMethod void myUnitTest() {
        Test.startTest();
        List<ID> ids= new ID[]{'0012800000Hz6ozAAB','0012800000Hz6oxAAB'};
        FutureSample.futuremethod(ids);
        Test.stopTest();
    }
}
  • Queueable

  Queueable接口有着相似future的特性,相似將future特性和批處理功能混合在一塊兒,相對future方法來說,有很大的優點:

  1.可使用Object和sObject類型做爲參數;

  2.便於監控,能夠直接經過System.enqueueJob()方法運行返回AsyncApexJob ,方法不用限制在startTest()和stopTest()方法中;

  3.能夠連接兩個job,一個Queueable接口方法能夠調用另外一個Queueable接口。

  Queueable在執行異步的時候大部分能夠替代掉future,可是不是全部的狀況均可以替換。當一個方法有時須要同步執行有時須要異步執行,相對來說用future操做更爲簡單,畢竟不須要修改方法的內容,只是註解而已。

Queueable接口代碼舉例:

public with sharing class QueueableSample implements Queueable{
	
	private List<ID> ids{get;set;}
	
	public QueueableSample(List<ID> ids) {
		this.ids = ids;
	}
	
    public void execute(QueueableContext qc) {
    	String sql = 'select Id,Name from Account where Id in :ids';
    	List<Account> accounts = Database.query(sql);
    	for(Account account : accounts) {
    		System.debug(account.Id);
    	}
    }
}

運行實現QueueableSample接口的類的方式以下:

 

@isTest
private class Test_QueueableSample {
    static testMethod void myUnitTest() {
        Test.startTest();
        List<ID> ids= new ID[]{'0012800000Hz6ozAAB','0012800000Hz6oxAAB'};
        QueueableSample sample = new QueueableSample(ids);
        ID jobID = System.enqueueJob(sample);
        Test.stopTest();
    }
}

  Queueable儘管很好用很強大,不過force.com對於Queueable有不少限制和規範,詳情請參看官方文檔。

  • ScheduledApex

   定時任務相對來講,使用比較方便。當你須要在指定時間日期去執行某些操做(好比按期清理垃圾數據等等)時,定時任務就顯得尤其便利。

  定時任務的聲明和調用都很簡單,經過如下步驟便可完成操做:

  1.實現Schedulable接口,並重寫execute方法,此方法體內實現須要定時執行的操做;

  2.使用System.schedule()方法實現定時任務的調用。

  Schedulable接口代碼舉例以下:

public class GoodsSchedule implements Schedulable {
	public void execute(SchedulableContext sc) {
		String queryString = 'select Id,GOODSNAME__c from GOODS__c';
		SimpleBatchUtil batchUtil = new SimpleBatchUtil(queryString);
		Database.executeBatch(batchUtil);
	} 
}

  上述代碼定義了一個定時任務,定時任務的方法體內實現批處理操做GOODS表

Schedulable接口調用以下所示:

@isTest
private class TestGoodsSchedule {

    static testMethod void myUnitTest() {
        String executeTime = '0 10 2 * * ?';
        GoodsSchedule goodsSchedule = new GoodsSchedule();
        System.schedule('batch goods',executeTime,goodsSchedule);
    }
}

注意:定時任務在每24小時同時只容許最多100個定時任務。超過數量則會拋出異常。

System.schedule()方法有三個參數:第一個參數爲定時任務名稱;第二個參數爲定時任務執行時間;第三個參數爲須要執行的定時任務的對象。

關於定時任務執行時間有不少須要注意的地方:

執行時間字符串經過空格分隔每一個時間點,時間點的順序爲:

Seconds Minutes Hours Day_of_month Month Day_of_week optional_year

每一個時間點的取值以下所示:

名稱 取值範圍 特殊字符
Seconds 0-59 NONE
Minutes 0-59 NONE
Hours 23 , - * / 
Day_of_month 1--31 , - * / ? L W
Month

1--12或者JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC

, - * / 
Day_of_week 1--7或者SUN,MON,TUE,WED,THU,FRI,SAT , - * / ? L #
optional_year null或者1970--2099 , - * /

特殊字符包含八種,下面是對他們的解釋:

 

特殊字符名稱 特殊字符解釋
, 定界值。好比Hours設置1,2則只有小時爲1或者2的時候執行
- 指定一個範圍。好比Day_of_week設置2-6則週一到週五執行
* 指定全部值。好比Day_of_month指定*則天天都執行
? 沒有指定特定的值,只在Day_of_month和Day_of_week中執行
/ /左側指定間隔什麼時間開始,/右側顯示間隔數量。eg:對於Day_of_month,指定1/5則每月的每一個第五天開始運行第一天
L 只應用於Day_of_month以及Day_of_week.用於Day_of_month表明當月最後一天,用於Day_of_week,表明每個月最後一個周幾.  eg : 1L表明每個月最後一個週日
W 只應用於Day_of_month.指定最接近與當天的工做日,好比指定20W,20爲週六,則值爲19,即星期五。若是指定1W,1爲週六,最接近的爲上個月,則不可取,取第三日,即週一。
# 只應用於Day_of_week.格式爲weekday#day_of_month。其中,#之前表明工做日1-7(週日-週六),#之後指定月的第幾天。eg:2#2表明每月第二個週一執行。

經過幾個例子舉例:

0 0 13 * * ?                         指定天天13點執行

0 0 22 ? * 6L                       指定每月最後一個週五22點執行

0 0 10 ? * MON-FRI              指定週一到週五10點執行

0 0 20 * * ? 2016                 2016年天天20點執行

 

Schedulable除了在代碼中經過System.schedule()方法啓動定時任務還能夠經過頁面設置啓動定時器。步驟以下:

1.點擊setup-->develop-->Apex Classes;

2.點擊Schedule Apex按鈕;

3.輸入Job Name,爲定時任務顯示的任務名稱,點擊Apex Class的查找按鈕選擇須要定時任務的實現Schedulable接口的類,設定時間,點擊保存;

4.定時任務建立成功,在setup-->Jobs-->Scheduled Jobs中能夠看到建立的定時任務了。

經過頁面設置啓動定時器和代碼的區別爲:使用頁面配置定時器沒法精確到分和秒。

因爲本人對於Salesforce也是一個小白,因此若是有的內容有錯誤,歡迎批評指正。若是有不懂的問題,能夠留言,你們共同探討。下一篇將描述簡單的數據增刪改查頁面的構建。

相關文章
相關標籤/搜索