Skip to main content
Register now for TDX! Join the must-attend event to experience what’s next and learn how to build it.

Verwenden von Batch-Apex

Lernziele

Nachdem Sie diese Lektion abgeschlossen haben, haben Sie Folgendes gelernt:



  • Batch-Apex-Syntax
  • Batch-Apex – bewährte Vorgehensweisen
Hinweis

Hinweis

Lernen Sie auf Deutsch? Beginnen Sie die Aufgabe in einem Trailhead Playground in der Sprache Deutsch und verwenden Sie für die Navigation die in Klammern angegebenen Übersetzungen. Kopieren und fügen Sie nur die Angaben in Englisch ein, da zur Überprüfung der Aufgabe Daten in Englisch benötigt werden. Wenn Sie die Aufgabe in Ihrer deutschen Organisation nicht bestehen, empfehlen wir Ihnen folgende Vorgehensweise: (1) Stellen Sie das Gebietsschema auf USA um, (2) legen Sie Englisch als Sprache fest (Anweisungen dazu finden Sie hier) und (3) klicken Sie erneut auf die Schaltfläche "Check Challenge" (Aufgabe überprüfen).

Weitere Details dazu, wie Sie die übersetzte Trailhead-Umgebung optimal nutzen können, finden Sie unter dem Badge "Trailhead in Ihrer Sprache".

Mit Trail Together einem Dozenten folgen

Möchten Sie bei diesem Schritt einem Dozenten folgen?

(Dieser Clip beginnt bei Minute 31:26, für den Fall, dass Sie zurückspringen und den Anfang des Schritts noch einmal sehen möchten.)

Batch-Apex

Batch-Apex wird für die Ausführung umfangreicher Aufträge (mit Tausenden oder gar Millionen von Datensätzen!) verwendet, die die normalen Verarbeitungsgrenzen sprengen würden.

Diese Funktionalität hat zwei riesige Vorteile:


  • Wird ein Batch nicht erfolgreich verarbeitet, werden nicht auch alle anderen, erfolgreich abgeschlossenen Batch-Transaktionen per Rollback zurückgesetzt.

Batch-Apex-Syntax

Meist genügt ein QueryLocator mit einer einfachen SOQL-Abfrage, um den Umfang der Objekte im Batchauftrag zu erzeugen.

Mit dem QueryLocator-Objekt wird die Obergrenze für die Gesamtzahl der von SOQL-Abfragen abgerufenen Datensätze umgangen und Sie können bis zu 50 Millionen Datensätze abrufen. Bei einer Iterable(iterierbaren) Komponente wird die Obergrenze für die Gesamtzahl der von SOQL-Abfragen abgerufenen Datensätze durchgesetzt.

Mit dem QueryLocator-Objekt wird die Obergrenze für die Gesamtzahl der von SOQL-Abfragen abgerufenen Datensätze umgangen und Sie können bis zu 50 Millionen Datensätze abrufen. Die standardmäßige Batchgröße beträgt 200 Datensätze.

  • Eine Referenz auf das Objekt Database.BatchableContext
  • Eine Liste mit sObjects wie etwa List<sObject> oder eine Liste parametrisierter Typen. Wenn Sie einen Database.QueryLocator nutzen, verwenden Sie die zurückgegebene Liste.

public class MyBatchClass implements Database.Batchable<sObject> {
    public (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
        // collect the batches of records or objects to be passed to execute
    }
    public void execute(Database.BatchableContext bc, List<P> records){
        // process each batch of records
    }
    public void finish(Database.BatchableContext bc){
        // execute any post-processing operations
    }
}

Aufrufen einer Batch-Klasse

Zum Aufrufen einer Batch-Klasse instanziieren Sie diese einfach und rufen dann Database.executeBatch mit der Instanz auf:

MyBatchClass myBatchObject = new MyBatchClass();
Id batchId = Database.executeBatch(myBatchObject);

Sie können optional auch einen zweiten scope-Parameter übergeben, um die Zahl der Datensätze anzugeben, die an die execute-Methode für jeden Batch übergeben werden soll.

Id batchId = Database.executeBatch(myBatchObject, 100);

Bei jedem Batch-Apex-Aufruf wird ein AsyncApexJob-Datensatz erstellt, damit Sie den Fortschritt des Auftrags nachverfolgen können. Expertentipp: Sie sollten diese Batchgröße begrenzen, wenn Sie in die Nähe von Obergrenzen kommen.

AsyncApexJob job = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors FROM AsyncApexJob WHERE ID = :batchId ];

Verwenden des Zustands in Batch-Apex

Batch-Apex ist normalerweise zustandslos. Jede Ausführung eines Batch-Apex-Auftrags gilt als separate Transaktion. Ein Batch-Apex-Auftrag, der 1000 Datensätze umfasst und die standardmäßige Batchgröße verwendet, gilt beispielsweise als fünf Transaktionen mit je 200 Datensätzen.

Wenn Sie in der Klassendefinition Database.Stateful angeben, können Sie den Zustand über alle Transaktionen hinweg beibehalten. Bei Verwendung von Database.Stateful behalten nur Instanzmitgliedsvariablen ihre Werte zwischen Transaktionen bei. Die Beibehaltung des Zustands ist nützlich, um Datensätze während der Verarbeitung zu zählen oder zusammenzufassen.

Batch-Apex-Beispielcode

Wenn Sie in der Klassendefinition Database.Stateful angeben, können Sie den Zustand über alle Transaktionen hinweg beibehalten. Nehmen wir an, in Ihrem Unternehmen lautet eine Geschäftsanforderung, dass bei sämtlichen Kontakten für Firmen in den USA die Rechnungsanschrift der Muttergesellschaft als Postanschrift angegeben werden muss. Leider geben Benutzer neue Kontakte häufig ohne die richtigen Adressen ein! In unserem nächsten Beispiel werden wir in unserem Batchauftrag Kontaktdatensätze aktualisieren und möchten die Gesamtzahl der betroffenen Datensätze verfolgen, damit wir diese in der Benachrichtigungs-E-Mail angeben können.

Die folgende Beispielklasse findet alle Accountdatensätze, die von der start()-Methode mit einem QueryLocator übergeben werden und aktualisiert die zugehörigen Kontakte mit der Postanschrift ihres Accounts.

public class UpdateContactAddresses implements
    Database.Batchable<sObject>, Database.Stateful {
    // instance member to retain state across transactions
    public Integer recordsProcessed = 0;
    public 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\''
        );
    }
    public 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;
    }
    public 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);
    }
}

Also, im Einzelnen geschieht Folgendes:

  • Die start()-Methode stellt die Sammlung aller Datensätze bereit, die von der execute()-Methode in einzelnen Batches verarbeitet werden. Die Methode gibt die Liste der zu verarbeitenden Datensätze zurück, indem sie Database.getQueryLocator mit einer SOQL-Abfrage aufruft. In diesem Fall fragen wir einfach alle Accountdatensätze ab, deren "Billing Country (Rechnungsanschrift Land)" auf "USA" festgelegt ist.
  • Jeder Batch mit 200 Datensätzen wird an den zweiten Parameter der execute ()-Methode übergeben. Die execute()-Methode stellt die Postanschrift jedes Kontakts auf die Rechnungsadresse des Accounts ein und erhöht den Wert von recordsProcessed, um die Anzahl der verarbeiteten Datensätze zu erfassen.
  • Nach Abschluss des Auftrags führt die finish-Methode eine Abfrage des AsyncApexJob-Objekts (eine Tabelle mit Informationen über Batchaufträge) durch, um den Status des Auftrags, die E-Mail-Adresse des Einreichers und andere Informationen abzurufen. Anschließend wird eine Benachrichtigungs-E-Mail an den Einreicher des Auftrags gesendet, in der die Auftragsinformationen und die Anzahl der geänderten Kontakte angegeben werden.

Testen von Batch-Apex

Da die Entwicklung und das Testen von Apex-Code Hand in Hand gehen, zeigen wir Ihnen nun, wie Sie die obige Batch-Klasse testen.

@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;
    }
    @IsTest
static void test() {
        Test.startTest();
        UpdateContactAddresses uca = new UpdateContactAddresses();
        Id batchId = Database.executeBatch(uca);
        Test.stopTest();
        // after the testing stops, assert records were updated properly
        Assert.areEqual(10, [select count() from contact where MailingCity = 'New York']);
    }
}

Da die Entwicklung und das Testen von Apex-Code Hand in Hand gehen, zeigen wir Ihnen nun, wie Sie die obige Batch-Klasse testen. Kurz gesagt: Wir fügen einige Datensätze ein, rufen die Batch-Apex-Klasse auf und prüfen, ob die Datensätze ordnungsgemäß mit der richtigen Adresse aktualisiert wurden. Dann erstellt sie für jeden Account einen zugehörigen Kontaktdatensatz. Diese Daten werden von der Batch-Klasse verwendet.

Note

Achten Sie darauf, dass die Anzahl eingefügter Datensätze nicht die Batchgröße von 200 erreicht oder übersteigt, da Testmethoden nur einen Batch ausführen können. Außerdem müssen Sie sicherstellen, dass das von der start()-Methode zurückgegebene Iterable-Objekt der Batchgröße entspricht.

Die setup-Methode fügt zehn Accountdatensätze mit "New York" als "Rechnungsanschrift Stadt" und "USA" als "Rechnungsanschrift Land" ein. Dann erstellt sie für jeden Account einen zugehörigen Kontaktdatensatz. Diese Daten werden von der Batch-Klasse verwendet. Der Auftrag wird nach dem Aufruf bis Test.stopTest ausgeführt. Asynchroner Code, der in Test.startTest und Test.stopTest enthalten ist, wird nach Test.stopTest synchron ausgeführt.

Zum Schluss verifiziert der Test, dass alle Kontaktdatensätze ordnungsgemäß geändert wurden. Dazu wird geprüft, ob die Anzahl der Kontaktdatensätze mit "New York" als Stadt der Postanschrift mit der Anzahl der eingefügten Datensätze (also 10) übereinstimmt.

Bewährte Vorgehensweisen

Der Aufruf von Database.executeBatch befindet sich innerhalb des Blocks Test.startTest und Test.stopTest. Hier ereignen sich all diese wundersamen Dinge. Der Auftrag wird nach dem Aufruf bis Test.stopTest ausgeführt.

Bewährte Vorgehensweisen:


  • Optimieren Sie jede SOQL-Abfrage zur Erfassung der Datensätze, damit sie so schnell wie möglich ausgeführt wird.
  • Minimieren Sie die Anzahl der erstellten, asynchronen Anforderungen, um Verzögerungen zu vermeiden.
  • Seien Sie extrem vorsichtig, wenn Sie vorhaben, einen Batchauftrag von einem Auslöser aus aufzurufen. Sie müssen garantieren können, dass der Auslöser nicht mehr Batchaufträge hinzufügt als laut dem Limit zulässig sind.

Ressourcen

Teilen Sie Ihr Trailhead-Feedback über die Salesforce-Hilfe.

Wir würden uns sehr freuen, von Ihren Erfahrungen mit Trailhead zu hören: Sie können jetzt jederzeit über die Salesforce-Hilfe auf das neue Feedback-Formular zugreifen.

Weitere Infos Weiter zu "Feedback teilen"