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
二)異步進程簡單介紹
異步進程用於在單獨的線程內來運行進程。異步進程是一個在後臺運行,不須要用戶等到任務結束的進程或者方法。異步進程好處不少,包括不須要用戶等待,節省響應時間等等。
異步進程主要有如下幾種形式:
類型 | 介紹 | 經常使用情景 |
Future方法 | 在本身線程中運行,直到資源可用才運行 | Web service callout. |
Batch Apex | 運行大量的Job,數量超過正常處理限制 | 數據DML操做 |
QueueableApex | 和Future相似,可是提供額外的工做鏈,容許完成更復雜的類型 | 執行順序處理操做與外部Web服務。 |
ScheduledApex | 指定時間運行apex | 固定時間的任務,例如每日或每週等任務 |
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接口有着相似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有不少限制和規範,詳情請參看官方文檔。
定時任務相對來講,使用比較方便。當你須要在指定時間日期去執行某些操做(好比按期清理垃圾數據等等)時,定時任務就顯得尤其便利。
定時任務的聲明和調用都很簡單,經過如下步驟便可完成操做:
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也是一個小白,因此若是有的內容有錯誤,歡迎批評指正。若是有不懂的問題,能夠留言,你們共同探討。下一篇將描述簡單的數據增刪改查頁面的構建。