26

I am writing a batch class which will get the records whose status picklist value is 'no response' and whose created date is before greater than or equal to 48 hrs and update the status to 'declined'.

Do I need to use Database.stateful here ?

global class SolicitaBatch implements Database.Batchable<sObject>{
String query;
String email;
Id toUserId;
Id fromUserId;

global Database.QueryLocator start(Database.BatchableContext BC)
    {
        Datetime dtime = datetime.now().addhours(-48);
        String query = 'select id,createdDate, Status__c from Solicitation__C  where createdDate <= :dtime and Status__c = \'No Response\' ';
        return Database.getQueryLocator(query);
    }

global void execute(Database.BatchableContext BC, List<Solicitation__C> scope){
    List<Solicitation__C> Sols = new List<Solicitation__C>();
    for(Solicitation__C s : scope)
    {
        s.Status__c = 'ABCD';
    }
    update scope;

} 

global void finish(Database.BatchableContext BC)
    {
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

        mail.setToAddresses(new String[] {email});
        mail.setReplyTo('batch@acme.com');
        mail.setSenderDisplayName('Batch Processing');
        mail.setSubject('Batch Process Completed');
        mail.setPlainTextBody('Batch Process has completed');

        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
}

3 Answers 3

66

The only time you need Database.Stateful is when the execute method modifies a class variable in a way meant to be used across multiple execute methods or in the finish method. The majority of batches you will ever write will not need Database.Stateful. It's important to know that using Database.Stateful will harm your batch's performance, because the class will be serialized at the end of each execute method to update its internal state. This extra serialization results in longer execution time.

If you're ever not sure if you need it, simply ask yourself two questions: (1) "Does one execute method need data from a previous execute method?", and (2) "Does the finish method need data from any previous execute method?" If the answer to both of these questions is no, then you do not need Database.Stateful. If the answer is yes, then you may want to use Database.Stateful. Keep in mind that there are alternative means to using Database.Stateful, such as storing data in a Custom Setting, which may offer better performance in some cases.

2
  • Can you please share other alternative ways besides writing data into custom setting, If there are any?
    – javanoob
    May 24, 2017 at 19:46
  • 1
    @javanoob Anything you can persist to the database would work. I've used a Document, for example, as well custom objects (e.g. a logging object). In theory, you could also use the platform cache, but I consider it too unreliable for that purpose, since it can be purged at any time by the system to make room for new data. Hitting the database for the same Document over and again each transaction is just about as fast as a Custom Setting, but does use a query to get the data back.
    – sfdcfox
    May 24, 2017 at 20:12
10

In your use case, maintaining state Database.Stateful is not required, it is just an update to the status for each scope. You are not holding any values for one scope to another scope.

According to the documentation Using State in Batch Apex

Each execution of a batch Apex job is considered a discrete transaction. For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter is considered five transactions of 200 records each.

If you specify Database.Stateful in the class definition, you can maintain state across these transactions. When using Database.Stateful, only instance member variables retain their values between transactions. Static member variables don’t retain their values and are reset between transactions. Maintaining state is useful for counting or summarizing records as they’re processed. For example, suppose your job processed opportunity records. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed.

If you don’t specify Database.Stateful, all static and instance member variables are set back to their original values.

The following example summarizes a custom field total__c as the records are processed.

global class SummarizeAccountTotal implements 
    Database.Batchable<sObject>, Database.Stateful{

   global final String Query;
   global integer Summary;
  
   global SummarizeAccountTotal(String q){Query=q;
     Summary = 0;
   }

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
   }
   
   global void execute(
                Database.BatchableContext BC, 
                List<sObject> scope){
      for(sObject s : scope){
         Summary = Integer.valueOf(s.get('total__c'))+Summary;
      }
   }

global void finish(Database.BatchableContext BC){
   }
}
0

It can be used to keep track of some writtings made in an execution that may prevent writtings in future ones of the same batch. Personnally I know I should have used it once or twice. Even if it is slower than regular batches, the ability to leverage a "context" is invaluable in some complex cases, can save tons of processing and ensure you stay away from governor limits.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.