Salesforce Savepoints

Transaction control is an important part of any system that interacts with a database and Salesforce has neat ways of implementing said control.

Anyone that’s worked with SQL databases will be familiar with savepoints and rolling back, and Salesforce has implemented similar constructs. For those who haven’t heard of these terms wikipedia describes them as

savepoint is a way of implementing subtransactions (also known as nested transactions) within a relational database management system by indicating a point within a transaction that can be “rolled back to” without affecting any work done in the transaction before the savepoint was created.

rollback is an operation which returns the database to some previous state.

As with most things, the importance of these two features is best demonstrated using examples.

You have a single method that inserts two object records which are related by a master-detail relationship. The code

[code language=”java”]
public void myMethod(){

Parent__c parent;

try{

parent = new Parent__c();

insert parent;

} catch (System.DmlException e){

System.debug(e);

}

/** Do Some processing **/

try {

Child__c child = new Child__c();

child.parent__c = parent.id;

insert child;

}

catch (System.Dmlexception e){

System.debug(e);

}

}
[/code]

If the DML operation on the Parent object record fails, the Child object record will have been inserted but not attached to any master record. These orphaned records probably get a bit sad because of, you know, the no parent situation. I get a bit sad too as these records float about my database taking up space; using potentially useful primary- and foreign-keys; and increasing query times. In addition to this they can leave VisualForce pages in awkward states.

Luckily savepoints and rollbacks are a piece of cake to implement and solve all these issues in one fell swoop. The revised code

[code language=”java”]
public void myMethod(){

// Any DML performed after this savepoint will be undone should a rollback occur

Savepoint sp = Database.setSavepoint();

Parent__c parent;

try{

parent = new Parent__c();

insert parent;

} catch (System.DmlException e){

System.debug(e);

}

/** Do Some processing **/

try {

Child__c child = new Child__c();

child.parent__c = parent.id;

insert child;

}

catch (System.Dmlexception e){

System.debug(e);

// Rollback the database to the state held at the time of defining the savepoint

Database.rollback(sp);

}

}
[/code]

And Bob’s your uncle. There are a few things to consider when working with savepoints(and rollbacks) that aren’t immediately apparent, viz.

  1. You can continue processing after a rollback but note that only database DML will be undone, variable values will not be rolled back.
  2. You cannot rollback across triggers, as triggers fire in a different context. In slightly more english terms, if you set a savepoint, fire a trigger, and then try to roll back to that savepoint you will get strange results. This one can be troublesome as the error message is a bit lame.
  3. You can only set five savepoints in all contexts. For this reason I find it’s usually a good idea to have a one-to-one ratio between class and test methods.

You can find other considerations in the Force.com Apex Code Developer’s Guide, but these are the ones I commonly encounter.

5 thoughts on “Salesforce Savepoints”

  1. Nice post but I would like to add 4th point in things to consider.
    4th point would be view state. when view state changes for a transaction then savepoint becomes null. This is important point to be considered in a big code.

    Reply
  2. Dear Wes,

    Nice Post Indeed . But can we solve a situation like, to retrieve more than 50000 records by SOQL using savepoint . For example:
    * If we are retrieving 50000 record (put SP1 at 25000 and sp2 at 50000) then failure happens at 50001 record.
    * In this case database.rollback(sp2) rolled it back to sp2 state .
    * Now , how can I proceed from here to further retrieve my plus 50000 records in the same context with my same old query(can we do same logic again for my next 50000 records with savepoint 🙂 )

    I know , it looks like little weird to you (if it is completely not possible with sfdc savepoint ) but i need to to know if it is possible .

    Otherwise , We have option like @readonly and batch apex . But ,if above approach works then it will be a very efficient way .

    Thanks and a very Happy Sunday ,
    Mayank Joshi

    Reply
  3. Technically, your child is actually the parent record and your parent is the child. Children always are the records that point up to/refer to the parent (i.e. Contacts (children) point up to the Account (parent) record via the Contact.AccountId field.)

    Reply
    • It’s been 5 years since I wrote this and despite it being viewed more thank 10k times you’re the first person to spot my silly mistake! Thanks 😉

      Reply

Leave a Comment