Salesforce Apex Batch 接口介绍

在 Salesforce 里如果需要处理成千上万的数据,但 Apex SOQL 每次最多只能查询50,000条数据,DML 可以操作的数据更少只有10,000条,所以在要处理更多的数据时,我们就可以使用 Apex 中的 Batch 来实现。顾名思义,Batch 就是将数据分块处理。这次在这里详细介绍一下 Batch 几个接口的使用。

Datebase.Batchable

这是创建 Batch 必须实现的接口,该接口封装了三个方法:

(1)start 方法

该方法用于查询数据,将数据封装到 Database.QueryLocator 或 Iterable,并传给 execute 方法。

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

需要注意的是,使用 Datebase.QueryLocator 最多可以查询五千万条数据,Salesforce 对 SOQL 查询条数的限制将不起作用,而使用 Iterable,限制依然存在。

(2)execute 方法

对从 start 方法获得的数据进行处理,例如增删改查等操作。execute 方法采用异步的方式执行,提高了数据处理速度。需要注意的是,每一个 execute 方法里 Apex 的 limits 和正常的 transaction 是一样的。

global void execute(Database.BatchableContext BC, list<P>){}  

每个 execute 方法执行都是一个独立的 transaction。例如,如果一个Batch 需要执行 1000 条数据,并且没有对 scope 进行限制,则默认是每次执行 200 条数据,五个 transaction 同时执行。如果第一个transaction 成功,但是第二个失败了,第一个 transaction 对数据的更新操作将不会回退。scope 最大是 2,000 条数据。

(3)finish方法

所有的 execute 执行完毕后,执行一次 finish 方法,我们可以在里做发邮件通知,汇总数据处理结果等。

global void finish(Database.BatchableContext BC){}  

Database.BatchableContext

Datebase.Batchable 接口提供的方法中,都需要Database.BatchableContext 对象作为参数,我们可以通过该对象的 getJobId() 方法查询 AsyncApexJob,对 Batch job 的进程进行追踪。

global void finish(Database.BatchableContext BC)  
{
    AsyncApexJob a = [SELECT Id, Status, NumberOfErrors,
         JobItemsProcessed, TotalJobItems, CreatedBy.Email 
        FROM AsyncApexJob WHERE Id = :BC.getJobId()];
}

Datebase.AllowsCallouts

如果需要在 Batch 中进行 HTTP 请求或者使用 Webservice 方法,则要实现 Database.AllowsCallouts 接口。

global class TestBatch implements Database.Batchable<sObject>, Database.AllowsCallouts{}  

这个接口对于做系统集成是有帮助的,当提示 callout 错误的时候,可以检查下有没有实现这个接口。

Datebase.Stateful

如果需要实例变量在每次 execute 方法执行后不清空,可以实现Database.stateful 接口。需要注意的是,只有实例变量适用,静态变量依然会重置回原始值。

例如,有的时候我们需要对 batch 操作的数据进行一些简单的求和处理。首先我们声明了一个整数类型的变量,初始值为 0,然后在 execute 方法中对变量进行累加操作,最后在 finish 方法中对结果进行一些处理。如果没有实现 Datebase.Stateful 接口, finish 方法中打印的变量值依然为0。

global class SummarizeAccountTotal implements Database.Batchable<sObject>, Database.Stateful  
{
    global final String Query;
    global Integer Summary;

    global SummarizeAccountTotal(String queryStr)
    {   
        Query = queryStr;
        Summary = 0;
    }

    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator(Query);
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        for(sObject s : scope)
        {
            Summary = Integer.valueOf(s.get('Total__c'))+Summary;
        }
    }

    global void finish(Database.BatchableContext BC)
    {
        system.debug(Summary);
    }
}

通过上面的介绍,希望大家对 Batch 的接口能有一个大致的了解。当然,batch 还有很多其他的功能,例如使用 System.scheduleBatch 方法在特定的时间执行 batch,使用 Apex Flex Queue 对 Batch Job 进行排序等,有兴趣的可以深入研究一下,下次再继续为大家介绍。

Vicky Zhang

Read more posts by this author.