0%

Database.Stateful

Database.Stateful是Salesforce内置的一个接口类,batchable job默认是无状态的,也就是说即使在batchable job类中定义了实例变量,这些变量在start/excute/finish函数执行时, 会被重新初始化,并不能保持运行过程中的状态。请看示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
global class TestBatchable implements Database.Batchable<SObject> {
private Integer idx = 1;

global List<SObject> start(Database.BatchableContext bc) {
System.debug('start exec, idx:' + idx);
Contact c1 = new Contact();
Contact c2 = new Contact();
List<Contact> l = new List<Contact>();
l.add(c1);
l.add(c2);
return l;
}

global void execute(Database.BatchableContext bc, List<SObject> records) {
idx += 1;
System.debug('execing, idx:' + idx);
}

global void finish(Database.BatchableContext bc) {
System.debug('finish exec, idx:'+ idx);
}
}

以上batchable job分两个batch运行后,

1
2
TestBatchable testBatchable = new TestBatchable();
Database.executeBatch(testBatchable, 1);

执行结果为:

start exec, idx:1
execing, idx:2
execing, idx:2
finish exec, idx:1

如果需要保持运行过程中的状态,需要batchable job实现Database.stateful接口,请看对比例子:

1
2
3
global class TestBatchable implements Database.Batchable<SObject>, Database.Stateful {
private Integer idx = 1;
...(和上面的代码相同)

同样将这个batchable job分两个batch运行后,执行结果为:

start exec, idx:1
execing, idx:2
execing, idx:3
finish exec, idx:3

可以看到,batchable job的excute接口串行运行,同时idx变量的状态得到保持。

另外值得一提的是,Database.stateful接口中并没有定义任何函数需要实例实现,这个比较少见,但是值得学习。此处stateful仅仅表述batchable实例的一个状态,通常我们设计类的时候,会将该状态设计成类的一个成员变量,在构造函数或者setter中配置这个状态。这样的坏处是,如果这样的状态位太多,会使得类很累赘。如果把这样的状态位设计成接口,由用户选择是否需要实现这些接口,设计可以变得更加优雅、简介。