什么是 Async Apex
在 Salesforce 中,Async Apex(异步 Apex) 是指在后台异步执行的 Apex 代码,不会阻塞用户的交互操作或当前事务。它适用于处理 大量数据、大计算量操作、或耗时任务。
为什么使用 Async Apex
Salesforce 的同步 Apex 有很多限制(如 CPU 时间、SOQL 行数),当你需要执行以下操作时,异步 Apex 是更合适的选择:
- 执行时间较长的逻辑处理
- 处理大批量数据(避免同步时超时或超限)
- 需要排队、定时、批次运行
- 在事务提交后执行某些后续操作
Async Apex 的类型(4大类)
| 类型 | 用途 | 特点 |
|---|---|---|
| Queueable Apex | 可排队执行的任务,逻辑清晰,可链式调用 | 支持链式、上下文更灵活,推荐使用 ✅ |
| Batch Apex | 批量处理大数据量记录 | 可处理超出 governor limit 的大数据 |
| Scheduled Apex | 定时执行任务(如每天凌晨3点发送报告) | 支持 Cron 表达式,周期性任务必选 |
| Future Method | 最简单的异步方法,轻量级使用 | 无法返回值、不支持链式、不推荐用于复杂逻辑 |
Queueable Apex
Queueable Apex 允许你将一个任务排入异步队列 (Flex Queue),由系统在稍后执行。
Queueable 接口
接口定义如下
public void execute(QueueableContext context);
方法说明:
- execute:必须实现,它是执行异步逻辑的主方法
- 参数 context:QueueableContext 提供上下文信息,如获取当前作业的 Job ID 例如在执行过程中输出当前 job 的 Id
public void execute(QueueableContext context) {
Id jobId = context.getJobId();
System.debug('Job ID: ' + jobId);
}
方法定义与调用
Salesforce 已经定义好 Queueable 接口,在定义 Queueable Apex 的时候,实际上是实现 Queueable 接口。
案例代码如下
public class MyQueueableJob implements Queueable {
public void execute(QueueableContext context) {
// 异步任务逻辑
List<Account> accts = [SELECT Id, Name FROM Account LIMIT 10];
for (Account a : accts) {
a.Name += ' - Updated';
}
update accts;
}
}
调用方法
ID jobId = System.enqueueJob(new MyQueueableJob());
链式调用案例
可以在一个 Queueable 任务中启动另一个,从而实现链式调用:
public class FirstJob implements Queueable {
public void execute(QueueableContext context) {
// 第一个任务逻辑
System.debug('First job running...');
// 链式启动第二个
System.enqueueJob(new SecondJob());
}
}
参数传递
Queueable 中默认是没有参数的,需要定义一个构造方法,实现有参构造。案例代码如下
public class SendEmailJob implements Queueable {
List<Id> contactIds;
public SendEmailJob(List<Id> contactIds) {
this.contactIds = contactIds;
}
public void execute(QueueableContext context) {
List<Contact> contacts = [SELECT Email FROM Contact WHERE Id IN :contactIds];
// 发送邮件等操作
}
}
该方法的调用方法调用 部分一致,只是在调用的时候需要传递相应参数。
Batch Apex
Batch Apex 是一种用于大数据量处理的异步 Apex 功能,允许你批量处理成千上万条记录,而不会触发平台的同步处理限制(例如 SOQL 查询行数或 DML 操作数的限制。
使用场景
Batch Apex 通常用于以下情况:
- 处理超过 50,000 条记录(超出同步限制)
- 大量数据清理或更新
- 定期执行的数据任务(可以结合调度器)
- 复杂的业务逻辑需要分段处理
Database.Batchable<SObject> 接口
public interface Database.Batchable<SObject> {
Database.QueryLocator start(Database.BatchableContext bc);
void execute(Database.BatchableContext bc, List<SObject> records);
void finish(Database.BatchableContext bc);
}
Database.Batchable<SObject> 接口包含 三个必须实现的方法:
start(Database.BatchableContext context): 定义要处理的数据源,返回一个 Database.QueryLocator 或 Iterable<SObject>
- 这是整个 Batch Job 的入口。
- 返回的数据会被拆成一个个“批次”传给 execute()。
- 使用 QueryLocator 时最多可处理 5000 万条记录。
execute(Database.BatchableContext context, List<SObject> scope): 对 start() 返回的数据进行处理。每个 scope 是一小批(比如 200 条)记录
- 每批数据是一个事务,单独消耗 governor limit。
- 每批默认最多 2000 条记录(调用 Database.executeBatch() 时设置)。
finish(Database.BatchableContext context): 当所有批次完成时调用一次。用于后处理,如:
- 发送通知
- 调用另一个 Batch 或 Queueable
- 记录日志等
方法定义与调用
案例代码如下
global class UpdateContactStatusBatch implements Database.Batchable<SObject> {
global Database.QueryLocator start(Database.BatchableContext BC) {
return Database.getQueryLocator('SELECT Id, Status__c FROM Contact WHERE Status__c = null');
}
global void execute(Database.BatchableContext BC, List<SObject> scope) {
for (Contact c : (List<Contact>)scope) {
c.Status__c = 'New';
}
update scope;
}
global void finish(Database.BatchableContext BC) {
System.debug('All contacts updated!');
}
}
调用方法
UpdateContactStatusBatch batch = new UpdateContactStatusBatch();
Database.executeBatch(batch, 200); // 每批处理 200 条记录
Scheduled Apex
Scheduled Apex 允许你在 Salesforce 中定时运行 Apex 类(类似于定时任务、计划任务),适合用来执行周期性或延迟的后台操作,例如每日报告生成、每周数据清理等。
使用场景
Scheduled Apex 通常用于以下情况:
- 定期清理旧数据:每周删除 90 天前未完成的记录
- 定时发送提醒邮件: 每天早上 8 点向销售发送提醒
- 定期同步外部系统: 每小时同步一次库存数据
- 自动重新计算数据: 每天重新计算得分、预算等指标
Schedulable 接口
public interface Schedulable {
void execute(SchedulableContext sc);
}
任何实现该接口的类必须实现 execute() 方法,这个方法是任务被调度时真正执行的内容。
方法定义与调用
案例代码如下
public class DailyContactUpdate implements Schedulable {
public void execute(SchedulableContext context) {
List<Contact> contacts = [SELECT Id, LastModifiedDate FROM Contact WHERE LastModifiedDate = LAST_N_DAYS:30];
for (Contact c : contacts) {
// 自定义处理逻辑
}
}
}
调用方法
System.schedule('Daily Contact Job', '0 0 7 * * ?', new DailyContactUpdate());
CRON 表达式格式
Seconds Minutes Hours Day_of_month Month Day_of_week Year (可选)
cron 示例如下:
| 表达式 | 含义 |
|---|---|
0 0 0 * * ? | 每天凌晨 12 点 |
0 30 9 ? * MON-FRI | 每周一到五上午 9:30 |
0 0 12 1 * ? | 每月 1 日中午 12 点 |
管理 Scheduled Job
可以通过 SOQL 在salesforce中查看当前有哪些schedule job
SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger
或者通过设置页面查看,步骤: Setup > Scheduled Jobs
Future Method
Future Method 是一种异步执行机制,用于在后台延迟执行耗时或非关键操作(例如 HTTP 请求、发送邮件、大量更新等),从而避免当前事务被阻塞或触发 governor limits。
@future 是一个注解(Annotation),用于声明一个方法将在 未来的异步上下文中 被执行。
使用场景
- 发送异步邮件: 避免触发器中执行 Messaging.sendEmail() 被 governor 限制
- 调用外部接口: 使用 @future(callout=true) 进行远程 HTTP 请求
- 更新大量记录: 延迟更新,规避触发器和 SOQL 限制
- 日志记录或操作追踪: 在后台写入审计日志或历史表
语法
@future
public static void myFutureMethod(String someParam) {
// 逻辑代码将在后台异步执行
}
也可以指定 callout=true 来支持 Web Service 调用:
@future(callout=true)
public static void callExternalService(String param) {
// 支持 HTTP 请求等远程调用
}
方法定义与调用
示例代码1: 发送异步日志
public class Logger {
@future
public static void writeLog(String message) {
Log__c log = new Log__c(Message__c = message);
insert log;
}
}
调用方法
Logger.writeLog('Record updated successfully');
示例代码2: 调用外部 HTTP 服务
public class ExternalApi {
@future(callout=true)
public static void callService(String param) {
HttpRequest req = new HttpRequest();
req.setEndpoint('https://api.example.com/data?query=' + param);
req.setMethod('GET');
Http http = new Http();
HttpResponse res = http.send(req);
}
}
使用限制
- 方法必须是 static,实例方法不能使用 @future
- 方法返回类型必须是,void 不支持返回任何值
- 方法参数类型限制,只能是 primitive 类型(如 String、Integer、Id),不能是对象或自定义类
- 每个事务最多调用 50 个 Future 方法
- Future 方法 不能互相调用
- 不支持在构造器、触发器递归中直接使用
- 不适用于复杂链式操作(推荐用 Queueable 替代)
使用注意事项(Governor Limits)
虽然是异步执行,但 Async Apex 也有 限制:
- Queueable 每个作业最多排队 50 次
- Batch Apex 单个批次最多返回 50 万条记录
- Future 方法不能调用另一个 Future 方法或批处理
- 所有异步操作总数也受 org 限制(异步 Apex 并非无限制)