如果您有很多記錄要處理,例如數據清理或歸檔,則Batch Apex可能是您最好的解決方案。
假設您要使用Batch Apex處理100萬條記錄。
對於要處理的每批記錄,一次調用批處理類的執行邏輯。
每次調用批處理類時,該作業都會被放置在Apex作業隊列中,並作爲離散事務執行。
此功能有兩個很棒的優點:
在批處理Apex中使用狀態
Batch Apex通常是無狀態的。批處理Apex作業的每次執行均被視爲離散事務。
例如,一個包含1,000條記錄並使用默認批處理大小的批處理Apex作業被視爲5個事務,每個事務200條記錄。
假設您有一項業務要求,其中規定,美國公司的所有聯繫人都必須以其母公司的Account 地址作爲其郵寄地址。
不幸的是,用戶正在輸入沒有正確地址的新聯繫人!
編寫一個Batch Apex類,以確保強制執行此要求。
global class UpdateContactAddresses implements
Database.Batchable<sObject>, Database.Stateful {
// instance member to retain state across transactions
global Integer recordsProcessed = 0;
global Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator(
'SELECT ID, BillingStreet, BillingCity, BillingState, ' +
'BillingPostalCode, (SELECT ID, MailingStreet, MailingCity, ' +
'MailingState, MailingPostalCode FROM Contacts) FROM Account ' +
'Where BillingCountry = \'USA\''
);
}
global void execute(Database.BatchableContext bc, List<Account> scope){
// process each batch of records
List<Contact> contacts = new List<Contact>();
for (Account account : scope) {
for (Contact contact : account.contacts) {
contact.MailingStreet = account.BillingStreet;
contact.MailingCity = account.BillingCity;
contact.MailingState = account.BillingState;
contact.MailingPostalCode = account.BillingPostalCode;
// add contact to list to be updated
contacts.add(contact);
// increment the instance member counter
recordsProcessed = recordsProcessed + 1;
}
}
update contacts;
}
global void finish(Database.BatchableContext bc){
System.debug(recordsProcessed + ' records processed. Shazam!');
AsyncApexJob job = [SELECT Id, Status, NumberOfErrors,
JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob
WHERE Id = :bc.getJobId()];
// call some utility to send email
EmailUtils.sendMessage(job, recordsProcessed);
}
}
測試批處理Apex
由於Apex開發和測試是並行進行的
@isTest
private class UpdateContactAddressesTest {
@testSetup
static void setup() {
List<Account> accounts = new List<Account>();
List<Contact> contacts = new List<Contact>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York', billingcountry='USA'));
}
insert accounts;
// find the account just inserted. add contact for each
for (Account account : [select id from account]) {
contacts.add(new Contact(firstname='first',
lastname='last', accountId=account.id));
}
insert contacts;
}
static testmethod void test() {
Test.startTest();
UpdateContactAddresses uca = new UpdateContactAddresses();
Id batchId = Database.executeBatch(uca);
Test.stopTest();
// after the testing stops, assert records were updated properly
System.assertEquals(10, [select count() from contact where MailingCity = 'New York']);
}
}
Create an Apex class that uses Batch Apex to update Lead records
LeadProcessor.apxc
global class LeadProcessor implements Database.Batchable<Sobject>
{
global Database.QueryLocator start(Database.BatchableContext bc)
{
return Database.getQueryLocator([Select LeadSource From Lead ]);
}
global void execute(Database.BatchableContext bc, List<Lead> scope)
{
for (Lead Leads : scope)
{
Leads.LeadSource = 'Dreamforce';
}
update scope;
}
global void finish(Database.BatchableContext bc){ }
}
LeadProcessorTest.apxc
@isTest
public class LeadProcessorTest
{
static testMethod void testMethod1()
{
List<Lead> lstLead = new List<Lead>();
for(Integer i=0 ;i <200;i++)
{
Lead led = new Lead();
led.FirstName = 'FirstName';
led.LastName = 'LastName' +i;
led.Company = 'demo' +i;
lstLead.add(led);
}
insert lstLead;
Test.startTest();
LeadProcessor obj = new LeadProcessor();
Database.executeBatch(obj);
Test.stopTest();
}
}