本篇知识参考:https://developer.salesforce.com/trailhead/force_com_dev_intermediate/asynchronous_apex/async_apex_batch

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,代码如下:

 global with sharing class GoodsBatch implements Database.Batchable<sObject>,Database.Stateful{
Integer queryCount = 0; String myEmailAddress = 'myAddress@xx.com'; global Database.QueryLocator start(database.BatchableContext bc )
{
String query = 'select GOODSPRICE__c,Id from GOODS__c';
return Database.getQueryLocator(query);
} global void execute (Database.BatchableContext bc, List<GOODS__c> goodsList)
{
for(GOODS__c goods : goodsList) {
Decimal price = goods.GoodsPrice__c;
price += 1;
queryCount +=1;
}
upsert goodsList;
} global void finish(Database.BatchableContext bc)
{
/*--------execute finish----------*/
/*注意:如果不实现Database.Stateful接口,则queryCount为0
因为在execute执行完成便会回滚到初始状态*/
System.debug('query count:' + queryCount);
//send email
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setToAddresses(new String[]{myEmailAddress});//set mail getter
email.setSubject('show count'); //set subject
email.setHtmlBody('query Count' + queryCount);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { email });
}
} 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也是一个小白,所以如果有的内容有错误,欢迎批评指正。如果有不懂的问题,可以留言,大家共同探讨。下一篇将描述简单的数据增删改查页面的构建。

salesforce 零基础开发入门学习(五)异步进程介绍与数据批处理Batchable的更多相关文章

  1. 【转载】salesforce 零基础开发入门学习(六)简单的数据增删改查页面的构建

    salesforce 零基础开发入门学习(六)简单的数据增删改查页面的构建   VisualForce封装了很多的标签用来进行页面设计,本篇主要讲述简单的页面增删改查.使用的内容和设计到前台页面使用的 ...

  2. salesforce 零基础开发入门学习(六)简单的数据增删改查页面的构建

    VisualForce封装了很多的标签用来进行页面设计,本篇主要讲述简单的页面增删改查.使用的内容和设计到前台页面使用的标签相对简单,如果需要深入了解VF相关知识以及标签, 可以通过以下链接查看或下载 ...

  3. 【转载】salesforce 零基础开发入门学习(五)异步进程介绍与数据批处理Batchable

    salesforce 零基础开发入门学习(五)异步进程介绍与数据批处理Batchable   本篇知识参考:https://developer.salesforce.com/trailhead/for ...

  4. 【转载】salesforce 零基础开发入门学习(一)Salesforce功能介绍,IDE配置以及资源下载

    salesforce 零基础开发入门学习(一)Salesforce功能介绍,IDE配置以及资源下载   目前国内已经有很多公司做salesforce,但是国内相关的资料确是少之又少.上个月末跳槽去了新 ...

  5. 【转载】salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解

    salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解   建立好的数据表在数据库中查看有很多方式,本人目前采用以下两种方式查看数据表. 1.采用schem ...

  6. 【转载】salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL)

    salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL)   salesforce中对于数据库操作和JAVA等语言对于数据库操作是有一定区别的.salesfo ...

  7. 【转载】salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句

    salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句 salesforce如果简单的说可以大概分成两个部分:Apex,VisualForce Page. 其中Apex ...

  8. salesforce 零基础开发入门学习(一)Salesforce功能介绍,IDE配置以及资源下载

    目前国内已经有很多公司做salesforce,但是国内相关的资料确是少之又少.上个月末跳槽去了新公司,主要做的就是salesforce,不过当时想要看一些相关资料确实比较难.为了避免想要零基础学习的人 ...

  9. salesforce 零基础开发入门学习(十一)sObject及Schema深入

    sObject在salesforce中占有举足轻重的位置,除了在数据库中数据以外,我们还应该关心一下他的元信息.元信息封装在Schema命名空间内. 作为面向对象语言,我们可以畅想一下如果我们是设计人 ...

随机推荐

  1. js生成验证码并检验

    <html> <head> <title>验证码</title> <style type="text/css"> #co ...

  2. Ubuntu下设置(增加/删除)开机启动项

    As said above, you have to edit /etc/xdg/autostart/ and either: remove the NoDisplay=true lines; or ...

  3. Strong name signature not valid for this assembly Microsoft.mshtml.dll

    Strong name signature not valid for this assembly Microsoft.mshtml.dll  http://social.msdn.microsoft ...

  4. Execution Order of Event Functions

    In Unity scripting, there are a number of event functions that get executed in a predetermined order ...

  5. .NET环境下导出Excel表格的两种方式和导入两种类型的Excel表格

    一.导出Excel表格的两种方式,其中两种方式指的是导出XML数据类型的Excel(即保存的时候可以只需要修改扩展名为.xls)和真正的Excel这两种. using System; using Sy ...

  6. Selenium中的几种等待方式,需特别注意implicitlyWait的用法

    摘:http://blog.csdn.net/pf20050904/article/details/20052485 最近在项目过程中使用selenium 判断元素是否存在的时候 遇到一个很坑爹的问题 ...

  7. HTTP协议中POST、GET、HEAD、PUT等请求方法以及一些常见错误

    (来源:http://www.tuicool.com/articles/Ermmmyn) HTTP请求方法: 常用方法: Get\Post\Head (1)Get方法. 取回请求URL标志的任何信息, ...

  8. MongoDB for C#基础入门

    笔者这里采用的是mongoDB官网推荐使用.net驱动: http://mongodb.github.io/mongo-csharp-driver/2.0/getting_started/quick_ ...

  9. Oracle PL/SQL块

    PL/SQL块 简介 :PL/SQL是 Procedure Language & Structured Query Language 的缩写,是ORACLE公司对标准数据库语言的扩展 PL/S ...

  10. Oracle Enterprise Manager打不开的解决方法

    之前OEM一直可以打开,但今天上班发现打不开了,输入http://localhost:1158/em 提示该网页无法打开. 那么检查一下: cmd进命令行 C:\Documents and Setti ...