异步处理
- Future Annotation
- 批处理任务
- 队列,实现 Queueable 接口
- 定时任务,schedule
Future Annotation
- Future 方法必须是静态方法,并且只能返回 void
- 参数只能是原始数据类型或者原始数据类型的数组或集合
- Future 方法不能调用另外一个 Future 方法
- 每24小时最多可调用25万个 Future 方法,或者您组织中的用户许可数量乘以200,以较大者为准
- (callout=true) 允许调用外部请求
global class FutureClass
{
@future(callout=true)
public static void myFutureMethod()
{
// Do Sth
}
}
批处理任务
// Database.Stateful 记录上下文中的数据
// Database.AllowsCallouts 允许调用外部请求
global without sharing class MyBatchClass implements Database.Batchable<SObject>,Database.Stateful,Database.AllowsCallouts {
public String query;
public Integer count;
// 调用批处理
// 如果有强验证规则导致单批次整体失败,即:Database.update(orderData, false);未能实现非事务更新
// 最后可能会剩下几百几千条数据,把批次调小或者调为1,重新运行,直至剩下全部不符合更新条件的数据
// MyBatchClass batchObj = new MyBatchClass();
// Database.executeBatch(batchObj, 200);
// 构造函数,可以动态传入where条件
global MyBatchClass(String whereStr) {
query = 'select Id,Name from Order where date >=' + whereStr;
count = 0;
}
// 开始批处理,返回的是QueryLocator,该方法执行一次
global Database.QueryLocator start(Database.BatchableContext bc)
{
return Database.getQueryLocator(query);
}
// 执行批处理(多线程分批处理),lists是分批查询的结果,该方法执行多次
global void execute(Database.BatchableContext bc, List<Order> scope)
{
// 累加count值
count++;
// do sth. 分批次批量处理lists
// 根据实际业务逻辑进行处理
if(scope.isEmpty()) {
System.debug('not data');
return;
}
// 遍历查询结果,设置新的字段值
List<Order> orderData = (List<Order>)scope;
for (Order od : orderData) {
od.Name = 'test';
}
try {
// 事务成功
// update orderData;
// 部分成功
// 如果有严格的验证规则或触发器,可能会导致整个批处理中的所有记录都受到影响,依然导致全部失败
Database.update(orderData, false);
System.debug('Success');
} catch (DmlException e) {
System.debug('Error: ' + e.getMessage());
}
}
// 批处理执行完成,可以做一些收尾工作,该方法执行一次
global void finish(Database.BatchableContext bc)
{
// 如果不实现Database.Stateful接口,那么count=0(依然是构造函数中的赋值),不会记录上下文的count++
System.debug(count);
// 与批处理相关的job的信息
AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id = :bc.getJobId()];
// 收尾工作,比如发送邮件
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 });
}
}
// 执行批处理
// 第2个参数500表示一次执行500条,取值范围:1-2000,默认值:200
// 比如一共20000条数据,一次执行500条,那么需要执行40次,上面累加的count就等于40
MyBatchClass mbc = new MyBatchClass();
Id = batchId = Database.executeBatch(mbc,500);
队列
队列用的比较少,一般用Future就行了
对顺序有需求或者需要嵌套异步处理的时候,可以考虑使用queue
// 定义队列任务
public class AsyncExecutionExample implements Queueable {
public void execute(QueueableContext context) {
Account a = new Account(Name='BestLove', Phone='13888888888');
insert a;
}
}
// 入队
ID jobID = System.enqueueJob(new AsyncExecutionExample());
// 查看任务运行状况
AsyncApexJob jobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob WHERE Id=:jobID];
// 队列中调用队列
public class AsyncExecutionExample implements Queueable {
public void execute(QueueableContext context) {
// Do Sth
System.enqueueJob(new SecondJob());
}
}
测试队列
@isTest
public class AsyncExecutionExampleTest {
static testmethod void test1() {
Test.startTest();
System.enqueueJob(new AsyncExecutionExample());
Test.stopTest();
// 等
Account acct = [SELECT Name,Phone FROM Account WHERE Name='BestLove' LIMIT 1];
System.assertNotEquals(null, acct);
System.assertEquals('13585530842', acct.Phone);
}
}
定时任务
- 1次最多100个定时任务
- 必须声明为 global 或 public
- 定时任务和批处理任务可以结合使用
- 也可以在后台设置 设置 -> APEX类 -> 计划 APEX
- 查看进行中的计划,设置 -> 搜索计划 -> 找到计划的作业
global class scheduledMerge implements Schedulable {
global void execute(SchedulableContext sc) {
// do sth. 定期执行
}
}
// 在开发人员控制台中执行此示例
scheduledMerge m = new scheduledMerge();
String sch = '20 30 8 10 2 ?';
String jobID = system.schedule('Merge Job', sch, m);