Skip to content

Database Transactions

MARS Engine automatically wraps every API script in a database transaction.
If your code finishes without throwing, the transaction is committed.
If an error occurs (or you call exit()), MARS rolls back everything so your data stays consistent.

Automatic Transaction Lifecycle

  1. TRANSACTION BEGIN – right before your script starts executing.
  2. Your code & SQL run – use db.query() or the Query Builder as normal.
  3. TRANSACTION COMMITonly if no uncaught exceptions were thrown.
  4. TRANSACTION ROLLBACK – if any uncaught error bubbles up, or if you terminate early with exit().

This means the zero‑boilerplate case is already safe: You get atomic, all‑or‑nothing behaviour for free.

Forcing a Commit Early - db.commit()

Occasionally you want to persist changes even if the script might fail later (e.g. audit logs, enqueue‑and‑forget jobs).
Call db.commit() right after the statement you want to guarantee:

js
let file        = param('file');
let badJsonStr  = param('jsonString', '{}');

db.query('INSERT INTO files SET fil_name = ?, fil_data = ?', file.name, file.data);
db.commit();                           // <-- force‑persist now

// even if JSON parsing explodes, the INSERT above is safe
let json = JSON.parse(badJsonStr);
write('message', 'ok');

db.commit() ends the current transaction and starts a new one so the rest of the script is still protected.

Explicit Rollback - db.rollback()

You can cancel the current unit of work at any time:

js
try {
  db.query('INSERT INTO orders (...) VALUES (...)');
  verifyPayment();            // may throw
} catch (e) {
  db.rollback();              // undo previous queries
  write('error', 'Payment failed, changes reverted');
  exit();
}

Calling db.rollback() discards all statements since the last implicit/explicit commit.

Best‑Practice Checklist

  • Group related writes inside the default TX; avoid long‑running transactions.
  • ✅ Use db.commit() sparingly-only for idempotent or irreversible events (e.g. log lines).
  • Never await external HTTP calls while a transaction is open; commit first, then call out.
  • ✅ Prefer one transaction per request; use background workers for bulk imports.

FAQ

QuestionAnswer
Do I need to call commit() in every API?No. MARS commits automatically when your script finishes successfully.
What happens if my script crashes after a commit()?Only statements after the commit are rolled back; earlier data stays.