Savepoints y rollback
Marcar un punto de la transacción y, si lo que viene después sale mal, volver a él: deshacer solo una parte, sin tirar todo lo anterior.
✓ En esta sub-lección
- 01Explicar qué se deshace automáticamente cuando una transacción falla.
- 02Usar Database.setSavepoint() y Database.rollback() para deshacer una parte concreta.
- 03Conocer lo que un rollback no deshace y lo que cuesta en límites.
La nutria: ¿Te acuerdas? · Repaso de la lección 4
Limits.getQueries() devuelve 95 y Limits.getLimitQueries() devuelve 100. ¿Qué significa?
Ya sabes que un error sin tratar deshace la entera. Pero a veces no quieres eso: quieres intentar un paso y, si falla, dejar la base de datos como estaba justo antes de ese paso, y seguir con lo demás. Para eso existen los .
La nutria: El paralelo de Admin
Lo que ya ocurre solo
Si la transacción termina con un error sin tratar, Salesforce no guarda nada de ella: ni tus inserts, ni lo que hicieron los flows, ni los triggers. Por eso un usuario nunca ve «media cuenta guardada». Esta red de seguridad es automática y es todo o nada. Los savepoints sirven para cuando quieres algo intermedio.
Marcar y volver
Savepoint sp = Database.setSavepoint(); // 📍 marca: la base de datos está así
Account acc = new Account(Name = 'Aurora Foods');
insert acc;
List<Contact> contacts = new List<Contact>{
new Contact(LastName = 'Nakamura', AccountId = acc.Id),
new Contact(LastName = 'Okafor', AccountId = acc.Id, Email = 'no-es-un-email')
};
List<Database.SaveResult> results = Database.insert(contacts, false);
Boolean anyFailed = false;
for (Database.SaveResult sr : results) {
if (!sr.isSuccess()) {
anyFailed = true;
}
}
if (anyFailed) {
Database.rollback(sp); // ↩ vuelve a la marca: ni cuenta ni contactos
}- 1. Savepoint sp = Database.setSavepoint();
- 2. insert acc;
- 3. Database.insert(contacts, false);
- 4. Database.rollback(sp);
EN LA BASE DE DATOS
Paso 1 de 5
El alta de Aurora Foods: una cuenta y dos contactos. Okafor trae el correo mal escrito. Pulsa Reproducir.
En este ejemplo el fallo se detecta mirando los SaveResult, como en la lección 2. En el Módulo 8 verás la otra forma habitual: capturar la excepción de un insert con try/catch y hacer el rollback dentro del catch. La mecánica del savepoint es la misma.
Lo que conviene saber antes de usarlo
- setSavepoint() y rollback() cuentan cada uno como una instrucción DML en los límites. No los metas en un bucle.
- El rollback deshace la base de datos, no tus variables. Después del rollback, acc sigue teniendo el Id que recibió en el insert. Si intentas insert acc otra vez, falla: un registro con Id no se puede insertar. Si necesitas reintentar, crea el objeto de nuevo o usa acc.clone() (Módulo 5).
- Los contadores de límites no vuelven atrás: las consultas y DML que gastaste antes del rollback siguen gastados.
- Solo deshace lo que se hizo después de esa marca, en esa misma transacción. No es un «deshacer» de ayer.
Dos detalles que se aprenden a golpes
- Un savepoint no es gratis: cada Database.setSavepoint() y cada Database.rollback() cuentan como una instrucción DML del límite de 150. Úsalos donde hay una unidad que proteger, no en cada línea.
- El rollback deshace la base de datos, no tus variables. Después de volver al savepoint, acc sigue teniendo el Id que recibió en el insert, aunque ese registro ya no exista. Si intentas insertarla otra vez tal cual, falla porque un insert no admite un Id: crea un registro nuevo o limpia el Id primero.
La nutria: Ya conoces el «todo o nada» de un guardado
La nutria: ¿Y por qué no un Flow? Roll Back Records se lo lleva todo