Can I prevent an insert to be rolled back even if my class (later) runs into an exception?

This is possible, but first a word on transaction scope and management...

Transaction Scope: It is important to understand a bit more about how the platform handles the transaction for DML operations executed. By default if you don't catch exceptions the platform will rollback any changes the request (controller action method etc) automatically. This helps avoid the situation where some records are written (those leading up to the error) and others not. If your planning on catching exceptions in your UI (as is most common in VF) or logging reasons you need to consider this.

Logging and Savepoints: The following illustrates both a simple logging pattern and how you might want to consider wrapping you logic up in Savepoint to manage the rollback consistently. The approach used here is to store up your log entries until the 'finally' block, then insert them into the database.

public with sharing class Logger 
{       
    public static void demo()
    {
        // Rollback to here if any errors occuring in the following
        System.Savepoint sp = Database.setSavepoint();
        try
        {
            // Perform some work
            Logger.log('Creating Test');
            Test__c test = new Test__c();
            insert test;
            Logger.log('Created Test');

            // Do some calculations that might generate exceptions...
            Integer bad = 0;
            bad = bad / 0;
            Logger.log('Done some calcs');

            // Perform some other work (which might also cause an exception)
            insert new Test_Child__c(Test__c = test.Id); 
            Logger.log('Created Test Child');
        }
        catch (Exception e)
        {
            // Log the exception
            Logger.log(e);  

            // Rollback everything done up until this point
            Database.rollback(sp);          
        }
        finally
        {   
            // Flush the log writing everything captured to the database        
            Logger.flush();
        }
    }

    private static List<Log__c> logs = new List<Log__c>();

    public static void log(String message)
    {
        logs.add(new Log__c(Message__c = message));     
    }

    public static void log(Exception e)
    {       
        logs.add(new Log__c(Message__c = e.getMessage(), StackTrace__c = e.getStackTraceString()));
    }

    public static void flush()
    {
        insert logs;    
    }
}

The following shows a successful log output and a failed one (with the divide by zero code in above).

enter image description here

Finally if your interested in a pattern that helps you better manage transactional scope (without having to liter your code with Savepoint logic), avoid the DML governor and a few other features, take a look at the Unit Of Work pattern described here.

NOTE: There are a few exceptions that cannot be caught in Apex (governors being the main example), in this case you cannot use your own logging approach as like it or not the platform will rollback everything here as the finally will never be called. You may want to consider using Subscriber Support access to view the platform debug logs in this cases. Maybe then even enhance the Logger.log method to also emit to System.debug (utilise LoggingLevel.Error will ensure messages are not truncated in larger logs).


As per How can I cause side effects outside an execution context?, Summer '17 now has Platform Events GA.

Note the following from the docs:

Platform Events and Transactions
Unlike custom objects, platform events aren’t processed within database transactions in the Force.com platform. As a result, publishing platform events can’t be rolled back. Note the following:

  • The allOrNoneHeader API header is ignored when publishing platform events through the API.
  • The Apex setSavepoint() and rollback() Database methods aren’t supported with platform events.

So any Platform Events that you publish before the transaction rollback occurs will be persisted. You could use a trigger on those events to insert the actual sObjects.


As long as the exception isn't fatal, you should be able to prevent the rollback. Are you able to add try-catch blocks to handle the types of exceptions you're experiencing or expect, perhaps log them and then exit gracefully (or continue if that's appropriate)?

Edited to add... I probably should have provided an example as below:

try{
If(lstsObject.fieldA==null) lstsObject.fieldA = 0;
   }catch(nullpointerexception){
     lstsObject.fieldA = 0;
   }catch(listexception){
      // list exception error
      // do something else A;
   }catch(exception e){
     // generic exception error
     //do something else B;
   }finally{
     // optional finally block 
     // code to run whether there's an exception or not
   }