Sunday, July 6, 2025

Savepoint & Rollback in Apex

In Salesforce Apex, Savepoint and Rollback work like an “undo” feature for database changes during a transaction. They help prevent unwanted data from being saved if something goes wrong in your code execution.

What is a Savepoint?

A Savepoint marks a specific stage in your transaction. Everything done before the savepoint is considered safe. If an error occurs after the savepoint, you can roll back to that point.

Savepoint sp = Database.setSavepoint();

What is a Rollback?

Rollback undoes all database changes made after a savepoint. It does not affect records inserted, updated, or deleted before the savepoint.

Database.rollback(sp);


Example 1: Using Savepoint and Rollback

Account acc1 = new Account(Name='First Account');

insert acc1;


// Set savepoint

Savepoint sp = Database.setSavepoint();


Account acc2 = new Account(Name='Second Account');

insert acc2;


// Simulate an error

if (true) {

    Database.rollback(sp);

}

Result:

  • acc1 is saved.
  • acc2 is rolled back.
  • No exception is thrown.


Example 2: Without Savepoint and Rollback

Account acc1 = new Account(Name='First Account');

insert acc1;


Account acc2 = new Account(Name='Second Account');

insert acc2;


// Simulate an error

if (true) {

    throw new CustomException('Something went wrong!');

}

Result:

  • Entire transaction fails.
  • Neither acc1 nor acc2 is saved.
  • A custom exception is thrown.


Why This Matters

Without Savepoints, any error rolls back all changes in the transaction. Even valid data that was saved before the error is lost.
With Savepoints, you can protect the valid part of the transaction and only undo the part that failed.


Real-World Use Case

Suppose you are creating three related records in one transaction:

  • An Account
  • A Contact
  • An Opportunity

If the Opportunity creation fails, you can use a savepoint before inserting it and roll back just that part — keeping the Account and Contact saved.


When to Use Savepoint and Rollback

  • When you want to protect only part of a transaction.
  • When you expect possible failures in specific DML operations.
  • When you want more control over error handling and data safety.


Limitations of Savepoint and Rollback in Apex

1. Rolling Back Invalidates Later Savepoints

If you create multiple savepoints and roll back to an earlier one, any savepoints created after that become invalid. Using those invalidated savepoints will cause a runtime error.

Example:

Savepoint sp1 = Database.setSavepoint(); // First savepoint


Account acc1 = new Account(Name = 'First');

insert acc1;


Savepoint sp2 = Database.setSavepoint(); // Second savepoint


Account acc2 = new Account(Name = 'Second');

insert acc2;


// Roll back to first savepoint

Database.rollback(sp1);


// Now sp2 is invalid. Using it will cause a runtime error

Database.rollback(sp2); // This line will throw an error


2. Savepoints Do Not Work Across Trigger Invocations

Each time a trigger is executed, it runs in a separate context. If you try to use a savepoint created in one trigger execution inside another, it will not work — even if stored in a static variable.

Step-by-Step Example:

Apex Class:

public class SavepointHolder {

    public static Savepoint sp;

}

Trigger Code:

trigger AccountTrigger on Account (before insert) {

    if (Trigger.isBefore) {

        if (SavepointHolder.sp == null) {

            // First trigger execution: set savepoint

            SavepointHolder.sp = Database.setSavepoint();

            System.debug('Savepoint set in first trigger run.');

        } else {

            // Second trigger execution: try to use old savepoint

            Database.rollback(SavepointHolder.sp); // This will throw an error

            System.debug('Trying to use savepoint from earlier run.');

        }

    }

}

Result:

  • First trigger run: savepoint is set.
  • Second trigger run: trying to use the same savepoint causes a runtime error.


3. Savepoints Count Against DML Limits

Salesforce enforces a limit of 150 DML operations per transaction. Every time you create a savepoint, it counts as one DML operation.

Example:

for (Integer i = 0; i < 150; i++) {

    Savepoint sp = Database.setSavepoint(); // Each counts as DML

}

Result:

  • DML limit is reached just by setting savepoints.
  • No room left for actual insert, update, or delete operations.
  • Transaction fails if more DML is attempted.

No comments:

Post a Comment