salesforce对于数据操纵个数以及次数有严格的限制,超过限制值则抛出异常。
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次
因为对于DML操作有限制,比如因为项目需求,需要修改50万条数据,直接调用Database.update()便会抛出异常,因为salesforce只允许一次性查出5万条数据并且只允许一次性修改1万条数据。如果需要达到目的,就只能使用批处理。
一)数据批处理Batchable
数据批处理适用于批量处理成百上千万的数据。批处理采用异步的处理方式处理数据,最多可以处理5000万条数据。新建一个批处理类需要实现Database.Batchable接口。此接口封装了三个方法,并且三个方法构成一个批处理的生命周期。start()方法用于查询数据,并将查询数据封装到List中;execute()方法用于操作数据,形参中List为start()方法中返回的数据,可以直接对此List进行修改以达到批处理行为。批处理全部执行后执行finish()方法,finish()方法用于进行一些后期处理,比如发邮件等操作。
需要注意的是:
1.start()方法执行后,数据便无法修改;
2.execute()原则上可以执行多次,比如在调用的时规定执行次数,则按照规定次数执行execute();
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