Inside a long transaction you want to undo the last few statements without losing everything done so far. Explain what a savepoint gives you, what it does not undo, and how it interacts with locks the transaction already holds.
answer
- Marker inside one transaction, rewind and continue
- Not a commit — nothing durable or visible yet
- Locks stay held; snapshot stays open
- Undoes DB state only, not memory or side effects
- Nested transactions = savepoints under the hood
basics
~20 sA savepoint is a named marker inside a transaction. Rolling back to it undoes data changes made after it while keeping earlier work and the transaction itself alive. It does not commit anything, does not make earlier work visible to others, and generally does not release locks already acquired.
solid answer
~60 sA savepoint marks a point inside an open transaction. Rolling back to it discards the data changes made since that marker and leaves everything before it intact, with the transaction still open — so you can continue, take another savepoint, and eventually commit or roll back the whole thing. Three limits matter: 1. **It is not a commit.** Work before the savepoint is still uncommitted and invisible to other sessions; a later full rollback discards it too. Durability comes only from COMMIT. 2. **Locks are not released.** Rows locked before or after the savepoint stay locked until the transaction ends, so partial rollback does not relieve contention. (The row versions written after it become dead, which the engine must clean up later.) 3. **Only database state is undone.** Files written, messages sent, and in-memory objects mutated are untouched — a frequent source of divergence between application state and database state after a partial rollback. The standard uses are batch error recovery (skip one bad row, keep the batch) and letting a framework emulate nested transactions.
go deeper
Define it as a marker you can rewind to inside a transaction, and be clear that it commits nothing.
Add that locks and the snapshot persist, that only database state is rewound, and name the two real uses: batch recovery and nested-transaction emulation.
Discuss savepoint overhead, per-chunk versus per-row strategy, application/ORM state reconciliation after a rewind, and why savepoints do not shorten a long transaction.
Frame when savepoint-based recovery is the right shape at all versus validate-first, chunked commits, or moving rejects to a dead-letter path, and set the convention for nested-scope semantics in the codebase.
## What a savepoint is A transaction is normally all-or-nothing. A savepoint adds an intermediate marker: a named position inside the open transaction that you can later rewind to. Rolling back to a savepoint discards every data modification made after it, keeps everything before it, and — crucially — leaves the transaction open and usable. The transaction as a whole still commits or aborts atomically at the end. Mentally, the transaction becomes a stack of markers. Setting a savepoint with a name that already exists pushes a new one and hides the old; rolling back to a name rewinds to the most recent one with that name and keeps it available for reuse. Releasing a savepoint discards the marker (and any nested inside it) without undoing the work — you simply lose the ability to rewind that far. Committing releases all of them implicitly. ## What it does not do **It does not commit.** This is the most common misunderstanding. Nothing before the savepoint becomes durable or visible to other sessions. If the transaction later rolls back entirely, or the process dies, all of it disappears. A savepoint is a *checkpoint of intent* inside your own transaction, not a partial commit. **It does not release locks.** Every row lock the transaction has taken is held until the transaction ends, and rolling back to a savepoint does not hand them back in the general case. So a savepoint gives you no relief from blocking, and it does not reduce the pressure a long transaction puts on the system. Similarly, the transaction keeps its snapshot, its identifier, and its position in whatever the engine tracks as the oldest running transaction. **It does not undo the outside world.** Anything that happened in application memory, on disk, or over the network during the rolled-back section is still done. After a partial rollback, in-memory entities may hold values that no longer exist in the database — an ORM in particular will happily flush that stale state later unless you clear or reload it. Treat "what does my application think is true now?" as an explicit part of the recovery. **It is not free.** Each savepoint creates bookkeeping the engine must track, and the rows written and then rolled back still consumed space and log volume; they become garbage for the cleanup machinery. Taking a savepoint per row across a very large batch has a measurable cost, which is why per-chunk savepoints usually beat per-row ones. ## Why it exists — the two real uses **Batch error recovery.** You are processing many items in one transaction and want a single bad item to be skipped rather than destroying the whole batch. Take a savepoint before each item (or each chunk); on failure, roll back to it, record the item as rejected, and continue with the next. Without this, the failure may leave the transaction in a state where the engine refuses further work until it is unwound, so the entire batch is lost. **Nested-transaction emulation.** SQL transactions do not truly nest. When an application framework offers "a new transaction inside an existing one", it is almost always implemented as a savepoint: entering the inner scope sets one, the inner scope failing rolls back to it, and the inner scope succeeding merely releases it. The semantics follow from the mechanism and are worth stating precisely — an inner failure does not abort the outer transaction, but an inner *success* is not durable either; it can still be thrown away when the outer transaction rolls back. Anyone expecting "the inner part committed regardless" needs a genuinely separate transaction on a separate connection instead. ## Practical guidance - Use savepoints for *expected*, recoverable per-item failures, not as a substitute for validating input before the transaction starts. Validating up front is cheaper than writing and rewinding. - Prefer per-chunk savepoints over per-row for large volumes, and re-run only the failed chunk item-by-item to isolate offenders. - Remember that a savepoint does not shorten the transaction. If the batch is long, that is a lock-hold and cleanup problem that only committing chunks solves. - After rolling back to a savepoint, reconcile application state deliberately: clear cached entities, and do not assume identifiers or generated values from the rolled-back section survived.
- If a framework's 'inner transaction' is a savepoint, what happens when the inner scope succeeds but the outer transaction later fails?The inner work is discarded along with everything else. Releasing a savepoint only drops the marker; it does not commit anything, so the inner scope's changes remain part of the outer transaction and share its fate. Code that needs the inner work to survive an outer failure — writing an audit or failure record, for example — must run in a genuinely separate transaction on its own connection, not in a savepoint-based nested scope.
- Does rolling back to a savepoint release locks taken after it?In the general case, no — locks acquired by the transaction are held until it commits or rolls back completely, so a partial rollback gives no relief to blocked sessions. The rewound modifications also leave dead row versions and log volume behind for later cleanup. If the goal is to reduce lock hold time or contention, the answer is to commit shorter units of work, not to add savepoints.
A savepoint is a checkpoint in a game level, not a save-to-disk: it lets you retry the last section without replaying the level, but quitting still loses the whole run.
saying these in an interview costs you the question
- Describing a savepoint as a partial commit that makes earlier work durable or visible
- Expecting rollback to a savepoint to release locks and unblock waiting sessions
- Assuming an ORM's in-memory objects revert along with the database state
- Taking a savepoint per row across a huge batch without considering the overhead
- Believing SQL transactions genuinely nest, rather than being emulated with savepoints