Batch Apex之Database.Stateful
前言
Database.Stateful是一个在Batch Apex常见的接口,官方文档: Using State in Batch Apex
正文
Batch Apex 作业的每次执行都被认为是一个离散事务。例如,一个包含1,000条记录并且在没有可选范围参数的情况下执行的批处理作业被认为是5个事务,每个事务有200条记录。
当使用Database.Stateful
-
只有实例成员变量在事务之间保留它们的值。
-
静态成员变量不保留它们的值,并在事务之间重置。
-
维护状态对于在处理记录时计数或汇总记录很有用。
-
例如,假设您的工作处理了机会记录。您可以定义一种执行方法,以便在处理机会总额时对其进行汇总。
如果没有指定 Databas.Stateful
- 所有静态和实例成员变量都会被重置为它们的初始值。
常见使用场景和弊端
唯一需要Database.Stateful的时候是当执行方法修改了一个类的变量,其方式是在多个执行方法或在结束方法中使用。
你所写的大多数Batch可能都不需要Database.Stateful。
重要的是要知道,使用Database.Stateful将损害你的批处理的性能,因为类将在每个execute方法结束时被序列化以更新其内部状态。这种额外的序列化会导致更长的执行时间。
如何确定你是否需要它
如果你不确定你是否需要它,只需问自己两个问题。
(1) "一个执行方法是否需要前一个执行方法的数据?"
(2) "完成方法是否需要之前任何执行方法的数据?"
如果这两个问题的答案都是 No,那么你就不需要Database.Stateful。
如果答案是 YES,那么你可能想使用Database.Stateful。
其他
请记住,还有其他方法可以替代使用Database.Stateful,比如在Custom Setting中存储数据,这在某些情况下可以提供更好的性能。
Apex Test
我个人在项目中写过一些对Batch的Test Class,我在这些Batch加了一些类变量,为了进行断言。
我在测试中发现,经常出现程序里打log看,明明是正常有值的,在测试Class里就是空的。
调查了一下发现,Batch执行完以后,类变量就会被清除掉了,所以必须把要给测试Class能访问到的类变量变为静态的。
这样才能让测试Class能成功进行断言。
像这样,给静态类变量加上 @TestVisible 注解,保证这个变量不会被别的正常类访问到,而测试Class能访问。
Start Execute Finish三个方法是三个独立的Transaction,在Developer Console里会出3次log,其中如果Start Return的是一个空的Database.QueryLocator,或者一个Iterable
public (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}