特殊时期,大家一定要保重身体。增强自身免疫力,一切都会过去,一起加油!!!

Apex Batch和Apex Scheduler-定时批处理大量数据

Salesforce zchao 2632℃ 0评论

我们在处理大规模数据时,经常会发生各种限制。但是使用Apex Batch会将需要处理的数据,分割开来执行。

也就是进行异步处理数据,而不会超出平台的限制。

同步和异步的概念:

生活中,同步就是表示两件事请同时做,比如一边听歌一边学习写作业。这两件事是同时进行。

生活中,异步就是表示两件事请有先后顺序,只能是先听歌,听完歌之后再学习写作业。这两件事是有顺序的进行。

软件程序中,完全是相反的,也就是同步是有顺序经进行,异步是同时进行。

同步:每个程序处理都是有顺序的,不能跨越执行,比如用户必须先注册,然后才可以登录,这个流程不能变。

异步:程序只是发送调用的指令,不用等待被调用的方法完全执行完,而是会继续执行下一个程序。就像打开一个页面,是边加载边显示在页面上。

同步是需要等待,异步不需要等待。

看一下英文表示,同步:Synchronize,异步:Asynchronous

 

批处理Apex语法

 

实现 :Database.Batchable 接口

和三个方法:

start()

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

Apex Batch开始,在Apex批处理作业的开始处被调用一次,收集并返回处理的对象或记录。

使用QueryLocator对象时,将忽略SOQL查询检索到的记录总数的限制条件限制,并且最多可以查询5000万条记录。

使用Iterable对象时,SOQL查询检索的记录总数的限制条件限制仍然适用。

execute()

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

接收start()传过来的对象或记录,默认批处理大小为200条记录。200条执行一次。

批处理记录开始它们倾向于按照从方法中接收到的顺序执行。但是,执行记录批处理的顺序取决于各种因素。无法保证执行顺序。

finish ()

global void finish(Database.BatchableContext BC){}

用于执行后处理操作(例如发送邮件,日志登录,调用其他Batch等),并且在处理完所有批次后调用一次。

 

批处理Apex类的框架如下:

global class MyBatchClass implements Database.Batchable<sObject> {
    global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
        // collect the batches of records or objects to be passed to execute
    }
    global void execute(Database.BatchableContext bc, List<P> records){
        // process each batch of records
    }    
    global void finish(Database.BatchableContext bc){
        // execute any post-processing operations
    }    
}

 

调用批处理类

MyBatchClass myBatchObject = new MyBatchClass();

Id batchId = Database.executeBatch(myBatchObject,200);

 

每次调用Batch Apex时,都会创建一个AsyncApexJob记录,以便跟踪工作进度。可以通过SOQL查看进度并管理Apex作业队列中的作业。

AsyncApexJob job = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors FROM AsyncApexJob WHERE ID = :batchId ];

 

下面看一个具体的例子,

当环境中有许多操作在一个对象上时,例如PB,Flow,Trigger等,我们对这个对象进行数据移行,需要更新等操作时,需要更加小心,

因为有可能会触发【Apex CPU time limit exceeded】,导致比如用dataloader更新,需要设置batch size为50,20,甚至为1,这样执行时间会大大加大。

Code more efficiently to avoid ‘Apex CPU time limit exceeded’

https://help.salesforce.com/articleView?id=000339361&language=ja&type=1&mode=1

Salesforce Developer Limits and Allocations Quick Reference

https://developer.salesforce.com/docs/atlas.ja-jp.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apexgov.htm

Maximum CPU time on the Salesforce servers5 10,000 milliseconds 60,000 milliseconds
Maximum execution time for each Apex transaction 10 minutes

 

数据移行时,有些Object需要直接更新,什么操作都不用,只是更新,为了让其他的PB等生效,设置上其相应的值。

也就是所谓的空更新,用dataloader做一个字段更新也可以实现,这里用Apex Batch来完成。

 

首先在Account对象上创建一个【空更新Flag】CheckBox字段。

 

global class AccountUpdateBatch implements Database.batchable<sObject> {
    global AccountUpdateBatch() {
    }
    global Database.QueryLocator start(Database.BatchableContext BC) {
        String query = 'select Id, Name, karakousin_Flag__c from Account';
        //return Database.getQueryLocator([select Id, Name, karakousin_Flag__c from Account]);
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<sObject> scope) {
        List<Account> accountList = new List<Account>();
        Account acc = new Account();
        for (sObject s : scope) {
            acc = new Account();
            acc = (Account)s;
            acc.karakousin_Flag__c = true;
            accountList.add(acc);
        }
        if (accountList.size() > 0) update accountList;
    }
    global void finish(Database.BatchableContext BC) {
           // Get the ID of the AsyncApexJob representing this batch job
           // from Database.BatchableContext.
           // Query the AsyncApexJob object to retrieve the current job's information.
           AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
              TotalJobItems, CreatedBy.Email
              FROM AsyncApexJob WHERE Id =
              :BC.getJobId()];
           // Send an email to the Apex job's submitter notifying of job completion.
           Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
           String[] toAddresses = new String[] {a.CreatedBy.Email};
           mail.setToAddresses(toAddresses);
           mail.setSubject('Apex Sharing Recalculation ' + a.Status);
           mail.setPlainTextBody
           ('The batch Apex job processed ' + a.TotalJobItems +
           ' batches with '+ a.NumberOfErrors + ' failures.');
           Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
  }
}

 

确认一下空更新Flag 字段。

 

通过匿名窗口执行,Apex Batch

 

回到页面 在确认空更新Flag 字段。

 

 

 

 

如果Batch类同时实现Database.Stateful,

可以指定保留这些事务之间的状态。Database.Stateful使用时,仅实例成员变量在事务之间保存值。

静态成员变量不会在事务之间保留其值,而是会重置。当您要计数或汇总正在处理的记录时,保持状态很有用。

例如,工作处理机会记录。执行 可以定义一个方法来汇总已处理的交易总数。

Database.Stateful 如果未指定,则所有静态成员变量和实例成员变量都将还原为其原始值。

 

第一种情况:Database.Stateful 未指定

上面加上

private Integer AUB_Count = 0;

global void execute(Database.BatchableContext BC, List<sObject> scope) {
AUB_Count += scope.size();
system.debug(‘AUB_Count = ‘ + AUB_Count);

}

打开 Debug logs,新建 User Trace Flags,

 

 

 

 

然后在执行Apex Batch,

先看一下 环境中有多少个 Account记录,

 

执行Batch后,

 

AccountUpdateBatch batch = new AccountUpdateBatch();
database.executeBatch(batch,40);

 

 

看 AUB_Count 处理记录数量

 

 

总共100条,第一次 40,第二次 40,第三次 20,不会加上之前的。

 

 

 

第二种情况:Database.Stateful 指定

 

global class AccountUpdateBatch implements Database.batchable<sObject>, Database.stateful{}

 

其他一样,

 

执行Batch后,一样的Batch Size=40,

 

 

 

总共100条,第一次 40,第二次 40,第三次 20,会加上之前的。

 

 

 

Apex Scheduler

上面是手动执行批处理,现在用Apex Scheduler可以在特定的时间执行Apex Batch。

 

实现Schedulable接口

 

Apex Scheduler语法

  1. global class scheduledBatchable implements Schedulable {
  2. global void execute(SchedulableContext sc) {
  3. batchable b = new batchable();
  4. database.executebatch(b);
  5. }
  6. }

 

scheduledBatchable reminder = new scheduledBatchable ();

// Seconds Minutes Hours Day_of_month Month Day_of_week optional_year

String sch = ’17 30 00 1 9 ? 2020′;

String jobID = System.schedule(‘Owners’, sch, reminder);

 

对上面的Batch操作。

global class AccountScheduled implements Schedulable {
global void execute(SchedulableContext sc) {
AccountUpdateBatch aub = new AccountUpdateBatch();
database.executebatch(aub);
}
}

AccountScheduled accsch = new AccountScheduled();
String sch = '00 31 16 1 9 ? 2020'; //表示 2020年9月1日,16:31:00
String jobID = system.schedule('Account Job1', sch, accsch);

1,通过匿名窗口执行

Apex Jobs

 

Scheduled Jobs

 

2,通过Schedule Apex执行。

 

 

 

 

设置为每周二的下午五点执行。

 

为了测试我设置为下午四点看效果。

 

Apex Jobs

 

Scheduled Jobs

这次只是简单的空更新Batch,更复杂的业务逻辑,都可以根据需要更改。

正常执行了,有问题或者建议可以评论区留言。

 

参考下面的链接。

Use Batch Apex Thrilhead

https://trailhead.salesforce.com/en/content/learn/modules/asynchronous_apex/async_apex_batch

Using Batch Apex

https://developer.salesforce.com/docs/atlas.en-us.226.0.apexcode.meta/apexcode/apex_batch_interface.htm

Schedule Jobs Using the Apex Scheduler

https://trailhead.salesforce.com/en/content/learn/modules/asynchronous_apex/async_apex_scheduled

Apex Scheduler

https://developer.salesforce.com/docs/atlas.en-us.224.0.apexcode.meta/apexcode/apex_scheduler.htm

 

我在故我思,我思故我在。

 

转载请注明:zchao博客之家 » Apex Batch和Apex Scheduler-定时批处理大量数据

喜欢 (9)or分享 (0)

您必须 登录 才能发表评论!