+ Start a Discussion
Case ManagerCase Manager 

BatchApex - System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

I am making a callout and then trying to insert the data and then immediately I make another callout followed by insert operation.  This process continues for users matching my criteria.  How to avoid below exception?

I know that its not allowed to do a callout and a DML in series.  But as per the requirement I need to follow this process.  

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

Note: I cannot use future method since I am running this process in a batch class.
 
James LoghryJames Loghry
This particular exception happens when you try to perform DML (insert, create, update, merge, etc) prior to making a callout.  So it's likely happening when you issue the second callout.  Unfortunately, you can't call future methods from batch jobs, so that will not work in this case.

What you should do, is find a way where you don't need to do Callout, then DML, then callout.  There's likely a way to architect, design around it.

However, if needed, you can chain batch jobs together.  You would perform the first callout and DML in one batch, then and then chain a second batch class that performs the second callout.  The chain happens by calling the second class in the finish method of the first batch class.

An example might look like the following:
 
global class BatchJob1 implements Database.Batchable<sObject>{

   global BatchJob1(){}

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator([Some query]);

   global void execute(Database.BatchableContext BC, List<sObject> scope){
        //Do callout

        //Do DML
    }

   global void finish(Database.BatchableContext BC){
        Database.executeBatch(new BatchJob2(),200);
   }
}

global class BatchJob2 implements Database.Batchable<sObject>{


   global BatchJob2(){}

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator([Some query]);

   global void execute(Database.BatchableContext BC, List<sObject> scope){
        //Do callout
    }

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

Note, if you need to pass variables between the batch jobs, then you'll want to look into implementing the Database.Stateful interface as well.
gbu.varungbu.varun
For the second callout you can use future mehod