异步 Apex 完全指南:Queueable、Scheduled、Batch 与 Future 方法
异步Apex完全指南:四种特性对比(Queueable推荐替代Future/Scheduled定期运行/Batch大数据分批/Future简单异步)→Queueable详解(enqueueJob返回Job ID/非原始类型传参/作业链接/延迟0-10分钟/堆栈深度控制AsyncInfo/测试stopTest同步执行/限制50个每事务+链式无限制/重复检测DuplicateSignature)→Transaction Finalizers(FinalizerContext四方法/独立事务/重新入队5次/5次计数重置/LoggingFinalizer示例)→Scheduler(Schedulable接口/System.schedule/Cron六字段/100作业限制/abortJob)→Batch Apex(Database.Batchable三方法/QueryLocator推荐/批大小1-2000/Flex Queue 100 Holding+5活跃/Stateful保持状态/stopTest同/5个QueryLocator限制)→Future方法(@Future static void/仅原始类型参数/callout=true)和大数据处理(Cursors+Queueable替代Batch优势)。
本课程共有 16 个章节
同学们,我们来看一下这一页幻灯片。这一页给大家概述了Apex里几种异步运行代码的方式。不过我先纠正一点:这里写的“同步运行”其实应该是,异步运行,,因为这些方法都是让代码在后台跑,不会让用户一直等着,待会你们就明白了。 咱们可以把异步执行想象成你在餐厅点餐:同步就是你站在柜台等菜做好,啥也干不了;异步就是你下完单拿个号,然后可以回座位刷手机,菜好了会叫你。在Salesforce里,有些操作可能需要很长时间,或者要处理超大量的数据,如果同步执行,系统资源会被卡住,用户体验也很差。所以就有了这几种后台处理的方式。 幻灯片上列出了四种,我们一个一个来讲: ,第一种:未来方法, 未来方法是最简单的一种异步调用。你只需要在方法前加上`@future`注解,告诉系统:“嘿,这个方法不用马上跑,有空的时候后台处理一下就好。” 它特别适合简单的长时间操作,比如调用外部的Web服务。不过它很简陋,你不能传复杂的对象(只能传基本类型),也没法知道任务跑得怎么样了,更不能一个任务跑完再自动触发下一个。就像你让朋友帮你寄封信,说完就走了,后面啥情况你也不知道。 ,第二种:批量Apex, 批量Apex专门用来对付海量数据。比如你要更新几万甚至几十万条记录,如果一次性处理,很容易撞到系统的调控器限制。批量Apex会把数据拆成一小块一小块(默认每块200条),然后一块一块地处理。它有三个阶段:`start`方法准备数据,`execute`方法处理每一块,`finish
同学们,今天我们来聊聊怎么选择最适合你需求的异步 Apex 功能。所谓异步,就是让代码在后台跑,不耽误当前的事务处理。 目前主要有四种:未来的方法、批量 Apex、可排队 Apex 和定时 Apex。我要帮你快速理清它们各自的特点,这样你写新代码的时候就知道该用谁了。 先说最简单的——未来方法。它的存在感很低,用法就是加上 `@future` 注解。当你在一个事务里需要进行长时间操作,比如调用外部服务,又不想让用户干等,就可以用它。但它的限制也明显:只能接收基本数据类型,不能是自定义对象,拿不到作业 ID,也没法链式调用。所以它适合“扔出去就不管”的轻量任务。 如果需要整批整批处理大量数据,那就要看批量 Apex 了。它能把成千上万条记录拆成一个个小批次,每批最多 200 条。关键是,每批开始的时候,Apex 的调控器限制都会重置,所以几乎不用担心超出限制。很适合数据清洗、大批量更新这种长期运行的作业。不过用起来稍微复杂一点,需要实现接口,写 start、execute 和 finish 方法。 现在 Salesforce 更推荐新代码使用可排队 Apex,也就是 Queueable。它可以说是未来方法的升级版:能得到作业 ID,可以传入复杂类型参数,还能链式执行,一个作业结束紧接着启动下一个。它还支持事务终结器,能把最终的提交或回滚状态传递给后续逻辑。灵活性高了很多,所以大多数新功能都优先考虑它。 还有定时 Apex,也就是 Scheduled。你只要设定一个 Cron 表达式,它就能按时执行,比如每天凌晨跑数据同步。它本身很简单,就是实现 Schedulable 接口。 最后还有一个组合技巧:把可排队 Apex 和定时 Apex 结合起来。让定时作业调用一个可排队作业,利用可排队的链式能力做并行处理。这样一来,就能获得类似批量 Apex 的灵活替代方案,同时更加轻量可控。 所以简单总结一下:只是想悄悄做点耗时的简单事,用未来方法;要大规模批处理数据,用批量 Apex;新写的复杂异步逻辑,尽量用可排队 Apex;需要定时触发,就用定时 Apex。你学会了吗?
同学们,今天我们来讲讲 Salesforce 中一个很实用的功能——可队列化的 Apex,也常被称为 Queueable Apex。你可以把它看作是未来方法(future method)的升级版推荐替代方案。以前我们常用未来方法来异步处理,但现在更推荐用这个。 那它怎么用呢?很简单,你实现一个叫 `Queueable` 的接口,然后通过 `System.enableJob()` 方法把你的作业提交到队列里。这个方法会返回一个作业 ID,有了这个 ID,你就可以很方便地监控作业状态了——既可以通过写 SOQL 查询 `AsyncApexJob` 对象,也可以直接在设置里的“Apex 作业”页面查看。 和未来方法相比,Queueable 有几个明显的好处。首先,它有一个作业 ID,能让你轻松追踪作业进度。其次,它支持复杂的成员变量,比如 sObject、自定义 Apex 类型,而未来方法只能传递基本类型。另外,它还支持作业链,也就是一个作业完成后,可以自动启动下一个作业,这样就能把复杂的异步流程串联起来。 而且,Queueable 的一些调控器限制比同步 Apex 更宽松,比如堆大小限制会更高一些。还有一个重要的行为:如果父事务回滚了,任何排队的作业都不会被处理,这保证了数据的一致性。 最后,要注意一点:当你把 Queueable 作业序列化时,声明为 `transient`(瞬态)的变量会被忽略,不会保存状态。所以如果你有不想被持久化的数据,记得标记成瞬态。 总结一下,Queueable Apex 功能更强大、更灵活,是处理异步任务的首选方式。好了,今天就讲到这里,下节课我们接着深入。
同学们好,咱们今天来看一个很实用的小知识点——`System.enqueueJob` 方法的延迟功能。这个方法呢,不仅可以帮我们把一个可调度的作业扔到异步队列里去执行,还能指定一个“最小延迟”时间,范围是 0 到 10 分钟。 你想象一下,如果咱们在代码里写 `System.enqueueJob(myJob, 5)`,意思就是告诉 Salesforce:“请至少等 5 分钟再开始执行这个作业”。注意这里的“至少”哦,实际开始的时间可能会比 5 分钟稍微晚一点点,但绝不会更早。 那这个延迟有啥用呢?最典型的场景就是跟外部系统打交道。比如外部接口有频率限制,或者轮询太频繁会把每天的调用配额用光。这时候,咱们就故意加一个延迟,让请求慢一点发出去,既保护外部系统,也保护咱们自己的限额。 还有个细节要记住:,在 Apex 测试里面,延迟会被直接忽略,,作业马上就会执行,这样测试就不用傻傻地等,可以跑得飞快。 另外,咱们管理员小伙伴可以在后台做一个很贴心的设置。对于那些没有明确指定延迟参数的作业,管理员可以配一个“默认组织级延迟”,范围是 1 到 600 秒。这样一来,即使开发同学忘了加延迟,平台也会自动加上一层保护,避免所有作业一窝蜂地冲出去。 最后我要特别提醒一句:如果你把延迟设置为 0,那作业就会尽可能快地跑起来。这在处理“链式作业”时很危险,因为一个作业结束立马触发下一个,如果没做好控制,眨眼功夫就可能把每天的异步 Apex 执行上限给打满了。所以,做链式作业时,一定要设计好“减速”或者“停止”机制,比如隔几秒再扔下一个作业,或者设置一个计数器,到了上限就暂停。 好了,这一小结就讲到这里,咱们消化一下,有问题随时问。
同学们,咱们今天来看一个非常有用的技巧,如何在 Salesforce 里控制那种“链式作业”——就是一个作业完成后,再自动触发下一个作业,一环扣一环。这种模式虽然灵活,但很容易失控,比如递归调用太深,或者一天之内提交的异步任务太多,超过了平台的上限。 好在平台给我们提供了一个安全阀门,那就是 ,System.enqueueJob, 配合 ,AsyncOptions, 里的 ,MaximumDeliverableStackDepth(最大可传递堆栈深度),。简单说,你可以给队列作业设定一个“最大深度”,比如 5 层。那么当作业一层层向下传递的时候,如果当前深度已经达到 5,它就不会再产生下一个作业了,链条自然终止。 那怎么检查和利用这个深度呢?,System.AsyncInfo, 类提供了几个非常方便的运行时方法,比如 ,hasMaxStackDepth(), 判断是否配置了最大深度,,getCurrentStackDepth(), 拿到当前作业是第几层,还有 ,getMaximumStackDepth(), 获取你设定的上限。另外它还能提供 ,getMinimumQueueDelayInMinutes(),,就是作业之间最小的延迟时间,有助于平滑作业的提交频率。 书本上给了一个经典的 ,Fibonacci 数列, 示例。Fibonacci 计算本来很适合递归,但在异步作业里如果无限制地链式调用,可能一天产生的作业数很快就会撞到每天的最大异步执行限制。所以在这个例子里,每次队列作业只计算一步,然后检查当前深度。如果还没到设定的最大深度,就创建下一个作业继续算;一旦,达到最大深度,就不再链接下一步了,而是把当前的中间结果直接保存到数据库里,,然后结束。这样既避免了无休止的链式作业,又保证不会超过每日的执行上限。 这种模式对于任何需要长时间运行、分步处理的链式操作都非常重要,因为你可以精准地控制资源使用——就像给一台机器装上了自动“熔断”装置,当深度或风险太高时,主动停下来,先把成果存好,而不是一股脑地往前冲,最后全被平台限制挡住,前功尽弃。 所以,下次你需要设计链式的异步作业时,一定要记得用上 ,AsyncOptions, 设定最大深度,配合 ,AsyncInfo, 来动态判断,打造一个稳健又可控的执行流程。这就是今天我们这一页幻灯片的精髓啦。
同学们,今天我们来聊一个特别实用的知识点——怎么测试可调度的作业,也就是 Schedulable 的 Apex 类。你要是在实际项目里写定时任务,那测试环节绝对不能马虎。 简单来说,测试的思路是这样的:你先把要测的调度作业提交上去,但这个提交一定要写在 `Test.startTest()` 和 `Test.stopTest()` 之间。为什么这么做呢?因为当代码执行到 `Test.stopTest()` 的那一刻,系统会一次性、同步地把之前你提交的所有异步任务全部跑完。这就给了我们一个非常方便的控制窗口。等执行完之后,你再去查询这个作业应该创建的那些数据,看看结果是不是符合预期,这样验证就完成了。 接下来要特别注意的,就是作业链,也就是所谓的 Chaining。如果你的调度作业在执行逻辑里,又提交了另外一个可调度作业,这就形成了一条链。但有一点要记牢:,每个父作业只能提交一个子作业,,不能在一个作业里一下子丢出一堆孩子。测试这种链式作业时,你要想清楚这个链条会有多深,可能会走到堆栈的极限,同时还要警惕调节器限制,比如总的 CPU 时间、查询次数等等。把链条设计得短一点,测试会更稳定。 还有一个细节:如果你的调度作业里面需要对外部服务发起标注呼叫,那这个类就一定要实现 `Database.AllowsCallouts` 接口,否则运行时会直接报错。实现这个接口就等同于告诉平台:“我这个作业会打出去打电话哦,请允许”。 最后,在测试链式调度作业的时候,建议你提前估算一下整个链执行下来会消耗多少资源,尽量控制堆栈深度,不要让测试因为达到调节器上限而失败。 好了,这些就是测试可调度作业的核心要点:用 `startTest` 和 `stopTest` 控制执行时机,查询数据去验证;链式作业只提交一个子任务,留意堆栈和调节器;需要标注时别忘了实现接口。把这些掌握了,写测试就很顺手了。
同学们,今天我们来看一下Salesforce里异步处理的一个重要机制——‘可操作限制’,以及它怎么防止同一个作业被重复执行,造成资源浪费。 首先,每个同步事务,也就是单次请求的处理过程中,最多只能往队列里放50个作业。但如果你用的是Express事务(一种轻量级的异步模式),那这个限制更严格,每次只能放1个作业。所以,别一次性扔太多进去,得规划好。 接下来,有个你们可能会担心的点——‘链接深度’。简单说,就是一个作业执行完后,能不能再触发另一个作业,形成链式调用。好消息是,除了Developer Edition和Trial组织限制最多5层之外,其他版本没有深度限制,你可以放心地串起来用。 那既然没有深度限制,系统怎么防止同一个作业被重复提交导致冲突呢?这里就用到了‘重复检测’。它通过一个叫DeliverableDuplicateSignature.Builder的机制,给每个作业生成一个唯一的签名。你可以在签名里加上字符串、ID或者数字,组合成独一无二的标识。当你要提交一个新作业时,系统会检查有没有相同签名的作业正在排队或运行。 如果有一个相同签名的作业已经在排队等待,那系统会直接抛出一个DuplicateMessage异常,阻止你重复提交。但如果同样的作业目前正在运行中,系统反而会放行你的新提交。为什么呢?因为一个作业在被取出来开始执行时,它的签名就会从队列里移除。这样,旧作业完成之后,你的新作业就能补上,保证至少有一个实例在那边跑着,不会漏掉。 所以整体上,Salesforce用这种机制既防止了无意义的资源争用,又保证了作业的最终执行,非常巧妙。 好,今天就讲到这里,有问题随时问。
同学们,今天我们来聊一个比较实用的话题——事务终结器,也就是Transaction Finalizers。听不懂没关系,我们把它拆开揉碎了讲。 先想象一下,你安排了一个定时任务,比如每晚自动给客户发邮件。万一这个任务执行失败了怎么办?你肯定希望它能自动重试几次,而不是一次失败就彻底罢工。事务终结器就是用来处理这种“失败重试”的帮手。 它怎么工作呢?用System.Finalizer这个接口,你可以把一段处理逻辑“附”在你的可安排作业上。当你的作业运行结束,不管是成功还是失败,系统会自动调用这段逻辑。重点是:如果失败了,这个终结器可以帮你把作业重新塞回队列里,而且最多能重复排队5次,超过5次就放弃了,防止无限循环。 每次执行这个终结器时,它会给你一个上下文对象,你可以通过它拿到一些关键信息:作业的ID、这次运行的请求ID、最终结果(要么是SUCCESS,要么是UNHANDLED_EXCEPTION),以及如果异常了,详细的异常信息。这样你就可以在日志里精准记录,或者根据不同的失败原因做不同的处理。 有一个要注意的规则:一个作业只能挂一个终结器,不能绑多个。而且,你原来的作业主体和这个终结器是在两个独立的事务中运行的。这是什么意思呢?就是说作业本身做的数据修改,可能在终结器运行时还没提交,或者已经回滚了,所以终结器里不要依赖作业中途的状态。 好消息是,调用终结器不算在你的每日异步执行次数配额里,不用担心它吃掉你的限额,你可以放心使用。 那代码里怎么写呢?很简单,在你的execute方法里,用System.attachFinalizer(yourFinalizer)把它附加上去就行了。终结器一般实现为一个实现了System.Finalizer接口的内部类或外部类。 最后给开发同学提个醒:如果你在托管包中写了一个全局的终结器类,而且里面有会修改自身状态的方法(比如计数),一定要特别小心。因为在升级包或不同版本共享时,这些可变状态可能引发意想不到的行为。尽量把终结器做得纯粹、无副作用,只做重试和日志记录,别在里面搞复杂的业务逻辑。 简单总结一下:事务终结器就是可安排作业的“急救员”,帮你自动重试失败任务,提供详细信息,不占配额,但每个作业只能有一个,且运行在单独事务中。它通过System.attachFinalizer()挂载,托管包里避免可变状态。 好,这一节就到这里。有什么问题,随时问。
好,同学们,我们来看一下这张幻灯片,它通过两个关键示例,给我们演示了终结器模式到底怎么用。 第一个示例叫做LoggingFinalizer。这个类同时实现了Schedulable接口和Finalizer接口,所以它既能被定时调度,又能充当终结器。它的思路很简单:当它作为一个可调度的作业开始执行时,会在运行过程中把各种日志消息先“缓冲”起来,也就是暂存在一个列表里。紧接着,它通过attachFinalizer把自己附加为终结器。这样一来,不管这个作业最终是成功还是失败,终结器的execute方法都会被调用,然后我们就可以在里面把缓冲的日志一口气提交出去。这有点像你出去采购,先在一张小纸条上随手记下每笔开销,最后不管采购顺不顺利,回到公司都会把纸条上的账目整理好交给财务。 第二个示例叫做RetryLimitDemo,它展示了怎么给失败的作业自动重试。假设我们有一个队列作业,执行过程中可能会因为网络抖动之类的原因失败。那我们就在它的终结器里做文章:一旦发现作业失败了,先检查一下重试次数,只要还没超过我们设置的5次上限,就重新把作业塞回队列。这样既避免了因为一点小问题就让整个工作泡汤,又通过上限避免无休止地重试下去,符合平台对链式作业深度的限制。 除了这两个示例,幻灯片还特别提醒我们一些常见的排错场景,这些对调试非常有帮助。比如说,你有可能不小心对一个作业附加了多个终结器;或者在调用attachFinalizer的时候,传入的对象根本就没实现Finalizer接口,也就是类型不对;再或者,你在不能附加终结器的上下文里调用了它,比如不在队列作业的执行范围内。所有这些错误,都会在调试日志里生成特定的错误信息,一看就知道哪里出了问题。另外,如果你配置了Splunk这样的日志分析平台,还能看到更丰富的错误详情,包括具体的作业ID和类ID,帮我们迅速锁定故障点。 好了,以上就是这两个关键示例以及相关的排查要点,希望大家能对终结器模式的理解更深一步。
好,今天我们来说一下Apex里的延迟执行,有时被形象地叫做“Apex收件箱”。意思呢,就是你可以把要跑的代码放进一个任务里,让它在你指定的时间自动触发,就像定时发送的邮件一样。 要实现这个,首先得让你的类实现一个叫 ,Deliverable, 的接口,并且重写里面的 `execute` 方法。这个方法会接收到一个 `DeliverableContent` 参数,你就在这里面写你真正想做的事情。 接着,怎么设定执行时间呢?我们用 `System.schedule` 这个方法,给它传入一个唯一的作业名称,还有一个 ,Cron 表达式,。Cron 表达式其实就是一个时间字符串,用来告诉系统“几点几分、哪一天”去跑这段代码。 那如果你想在这个定时任务里再安排一个批处理作业呢?你可以在 `execute` 方法中调用 `Base.executePoker()`,它能帮你把批处理塞进执行队列。或者用更简单的方式:直接调用 `System.schedulePoker()`,这一个方法就搞定了。 如果你需要追踪这个任务的状态,甚至想中途取消它,可以通过 `DeliverableContext` 的 `getTriggerID()` 方法拿到一个 ,CronTrigger ID,。这个 ID 就像任务的身份证,拿着它,你就能查看进度或者终止执行。 还有一点要特别注意:调度程序是作为系统来运行的,也就是说,不管当初创建任务的用户权限怎么样,任务里涉及到的所有类都会完整执行,完全不受用户权限的限制。所以用它的时候,要心里有数——它不会因为权限不足而停下来。 整体就是这样,你只需要写好类、配好时间,再把任务交给“收件箱”,Salesforce 就会按时帮你跑起来。
同学们好,今天我们来聊聊 Apex 里的定时任务,也就是怎么让代码在将来某个时间自动运行。这部分内容会涉及两个重点:一个是 Cron 表达式,另一个是 System.scheduleBatch 方法。 先看 Cron 表达式。它的格式是这样的:秒、分钟、小时、一个月中的第几天、月份、星期几,最后还可以带一个可选的年份。注意,秒排在最前面,这点跟很多其他语言的顺序不太一样。 为了灵活地表达时间,Cron 提供了一些特殊字符。逗号用来列出多个具体的值,比如“分钟”位置写 5,10,15 就代表第 5、第 10 和第 15 分钟。破折号表示范围,像星期一到星期五就可以写成 MON-FRI。星号代表所有可能的值,比如“月份”位写 * 就是每个月都触发。斜线用来描述增量,像 */5 在“分钟”位就表示每隔 5 分钟。还有 L 代表最后,比如 L 用在“日”的位置上就是当月最后一天。W 代表最近的工作日,15W 的意思就是最靠近 15 号的那个工作日。# 表示第几个星期几,比如 2#3 就是第三个星期一。这些组合在一起,可以定义各种各样复杂的调度规则。 不过,Apex 对 Cron 调度有一个很重要的限制:每小时最多只能触发一次。也就是说,你不能让同一个调度作业每隔 10 分钟就
同学们,今天我们来聊聊怎么测试 Salesforce 里头的定时作业,也就是 Scheduled Apex。 咱们先看重点:,测试定时作业,。在测试类里,如果你直接调用 `System.schedule()`,它是异步的,不会马上跑。那怎么让它马上执行呢?答案很简单——用 `Test.startTest()` 和 `Test.stopTest()` 包起来。这样,计时器就会被“骗”过去,系统会同步执行你安排的那个作业,方便我们验证结果。 那怎么跟踪这个作业跑没跑、什么时候再跑呢?你可以查一个叫 ,CronTrigger, 的对象。通过 SOQL 查询它,你能拿到两个关键字段:`TimesTriggered`(已经触发了多少次)和 `NextFireTime`(下次什么时候触发)。如果想再详细点,知道作业的名字和类型,还可以关联查询 ,CronJobDetail,,里面存着作业的名称和 `JobType`。 说到 `JobType`,有个小技巧:当你计算所有计划 Apex 作业时,记得过滤 `JobType = '7'`,这个数字 '7' 就是代表计划 Apex 作业。 接下来咱们得知道系统的,限制,:一个 Salesforce 环境里,最多只能有 100 个计划作业。而且,所有非正式员工(比如合作伙伴用户)加起来,每天总共只能执行 25 万次计划作业。这里要注意,我说的“临时工”实际上是指各种 license 类型的用户,他们共享这个限额。 最后,讲几条,最佳实践,: - 从触发器里直接安排计划作业要极其谨慎,很容易碰到限制。最好把具体的业务逻辑委托给一个单独的类去处理。 - 如果你的计划作业需要跟外部系统交互,记得用能支持 callout 的接口(比如 `Database.AllowsCallouts`)。 - 系统维护或者停机之后,有些计划作业可能会暂停,你要记得写脚本或者手动去重新安排它们。 - 沙箱刷新之后,所有计划作业都会被清掉,因为沙箱是从生产环境克隆的快照,所以你得重新部署或安排。 - 还有一点,作业的状态在整个运行过程中会一直保留,除非你用了“临时性”的作业(transient),那种作业跑完就自动清理了。所以正常作业的状态是一直存在的。 好了,这些就是关于定时作业测试和管理的核心要点,有什么问题随时提出来。
同学们,今天我们一起看一下批量处理Apex。简单来说,批量Apex能把海量数据拆成一小块、一小块来分别处理,这样既不会超时,也不会突破平台的各种限制。 要想使用批量处理,你的类必须实现一个叫 Database.Batchable 的接口。这个接口定义了三个核心方法:start、execute 和 finish。 第一个方法是 start。它的任务是收集需要处理的数据。你可以返回两种东西:一种是 Database.QueryLocator,它其实就是一个查询定位器,能用一条 SOQL 语句直接圈定最多五千万条记录,而且不会受普通事务里五万条 SOQL 行数的限制;另一种是返回一个 Iterable,也就是一个自定义的可迭代集合,但这时就会受到五万条 SOQL 行数限制的约束,所以一般用于从外部系统导入数据这种场景。 第二个方法是 execute。这个方法会真正处理每一块数据。参数里拿到的 scope 就是一个批次的记录列表,默认是两百条。关键的一点是,每一次 execute 执行开始的时候,Salesforce 上的调控器限制,也就是 governor limits,会被重置。所以每个批次都能拥有自己全新的限制额度,不用担心上一批把 CPU 时间或查询次数用完。 第三个方法是 finish。它负责收尾,在所有批次都处理完之后执行。你可以在这里发送总结邮件、做数据清理或者启动下一个批处理作业,非常适合做后处理通知。 此外,这三个方法都会传进来一个叫 BatchableContext 的上下文变量。这个上下文可提供 getJobID 方法,拿到这个任务 ID 后,你可以再去查询 AsyncApexJob 对象,就能随时监控作业的执行状态,比如失败了没有、处理了多少记录、还剩多少批等等。 最后,一个经典的例子就是 SearchAndReplace 模式。思路特别简单:在 start 里查询出要修改的记录,在 execute 里把特定字段值替换成新值,最后在 finish 里发邮件通知管理员任务完成。整个流程就是查询、更新、批处理这三步,学了它你就迈出批量Apex的第一步了。
同学们,今天我们来聊聊怎么在 Salesforce 里提交和处理大批量的数据。你想想,如果要更新上百万条记录,一次全做肯定超时,这时候就需要一个“分批作业”的机制,叫做 Batch Apex。 咱们就从一个核心方法讲起,它叫 `Database.executeBatch`。注意啊,有些文档里可能误写成“executePoker”,那是笔误,正式名字是 `executeBatch`。这个方法就是用来启动一个批处理作业的。你调用它时,它会返回一个作业 ID,类型是 `AsyncApexJob ID`。有了这个 ID,你就可以随时监控作业的进度,比如查查处理了多少条、有没有失败。 这个 `executeBatch` 方法还可以带第二个参数,叫 ,作用域参数,。它控制着每一批要处理多少条记录。默认可能是 200,但你可以调,比如有些应用像 Creditum 这个对象,你最多能设到 2,000 条。为什么要有这个限制?因为每批的执行时间不能超过两分钟,设置合理的大小能避免超时。 那批作业提交之后去哪里了呢?它会进入一个叫 ,Apex Flex 队列, 的地方。这个队列最多可以放 100 个处于“等待”状态的作业。这就好比拿号排队,如果有人插队怎么办?别担心,你可以手动重新排序,用 Salesforce 的设置界面,或者用 `System.FlexQueue` 这个类提供的几个方法,把重要的作业往前挪。默认情况下,队列是按先进先出的顺序执行的,也就是先排队的先处理。 但是,队列里排队的作业再多,Salesforce 同一时间最多只能处理 5 个批作业并发运行。所以,即使你排了 50 个,也只有前 5 个在跑,其他的在等待。 好,接下来是批作业内部的状态保持。你可能会想,我能不能在批处理的过程中累加一个变量,比如统计总共成功的记录数?当然可以,但你需要让这个批处理类实现 `Database.Stateful` 接口。这个接口的作用是告诉系统:“我的实例变量在批次之间不要重置”。注意了,如果不实现 `Stateful`,每次执行下一个批次时,你的实例变量都会被清空,而静态变量更不用说了,它们永远都会被重置。所以如果你想在多个批次间计数或者汇总数据,记着一定加上 `implements Database.Stateful`。 最后,如果你想在未来的某个时间点自动运行一次批处理,而不是马上运行,你可以用 `System.scheduleBatch` 方法。它跟可调度的 Apex 不同,你不需要实现 `Schedulable` 接口,直接调用这个方法,指定批处理类和作业名,再给一个时间表达式,它就会在那个时间启动一次批处理,跑完就结束。 总结一下,今天我们学了怎么提交批处理:用 `executeBatch` 返回 ID 监控,设置作用域大小,理解 Flex 队列的容量和顺序,实现 `Stateful` 来保存状态,以及用 `scheduleBatch` 安排未来作业。这些就是批处理作业最核心的知识点,下节课我们接着看怎么处理错误和用测试方法来验证它们。
各位同学,咱们今天来看看批处理Apex在测试和一些限制方面的要点。这些内容比较零散,但是很实用,我会尽量用大白话讲清楚。 首先说说测试批处理Apex。在写测试代码的时候,我们要把批处理执行的部分放在 `Test.startTest()` 和 `Test.stopTest()` 之间。当你调用 `Test.stopTest()` 的时候,Salesforce会立刻同步执行你排队的那个批
好,同学们,我们来看这一页,讲讲Future方法还有它的一些替代方案。 首先,Future方法在Apex里,可以说是最简单的异步交付机制。你只要在一个静态的、返回值为空的方法上,加一个@Future注解,这个方法就会在后台异步执行。但是要注意,它有很大的限制:参数只能用基本类型,像String、Integer这些,不能传sObject对象。你一般会在需要做外部标注调用的时候用它,也能靠它来绕开混合DML操作时遇到的那些麻烦事。 不过呢,现在官方更推荐大家用Queueable Apex来写新的异步逻辑,别再一上来就只顾着Future了。Queueable可以传复杂参数,还能链式调用,灵活得多,基本上已经可以替代Future的大部分使用