我们在处理大规模数据时,经常会发生各种限制。但是使用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类的框架如下:
调用批处理类
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
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语法
- global class scheduledBatchable implements Schedulable {
- global void execute(SchedulableContext sc) {
- batchable b = new batchable();
- database.executebatch(b);
- }
- }
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
2,通过Schedule Apex执行。
设置为每周二的下午五点执行。
为了测试我设置为下午四点看效果。
Apex Jobs
这次只是简单的空更新Batch,更复杂的业务逻辑,都可以根据需要更改。
正常执行了,有问题或者建议可以评论区留言。
参考下面的链接。
Use Batch Apex Thrilhead
https://trailhead.salesforce.com/en/content/learn/modules/asynchronous_apex/async_apex_batch
Using Batch Apex
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
我在故我思,我思故我在。
Latest posts by zchao (see all)
- Auraでアクションボタン作成して画面のチェックボックス項目一括処理 - 2021年4月12日
- デフォルト項目値を含むレコード作成実例説明(defaultFieldValues) - 2021年1月9日
- Salesforce のノーコード・ローコード開発 - 2020年12月31日