Transactions
Hysteria ORM provides robust transaction support for SQL databases, allowing you to group multiple operations into a single atomic unit. Transactions ensure data consistency and integrity, supporting features like rollback, isolation levels, nested, concurrent, and global transactions.
Basic Usage
Use startTransaction
with a callback to run operations within a transaction. If an error is thrown, the transaction is rolled back automatically.
import { sql } from "hysteria-orm";
import { User } from "./models/user";
// Automatically commits the transaction
await sql.startTransaction(async (trx) => {
await User.insert({ ...data }, { trx });
});
If an error occurs, changes are not committed:
import { sql } from "hysteria-orm";
await sql.startTransaction(async (trx) => {
await User.insert({ ...data }, { trx });
throw new Error("Test error"); // Transaction is rolled back automatically
});
// Raw transaction without models
await sql.startTransaction(async (trx) => {
await trx.sql.query("users");
});
Custom Isolation Level
You can specify a transaction isolation level:
await sql.startTransaction(
async (trx) => {
await User.insert({ ...data }, { trx });
},
{ isolationLevel: "SERIALIZABLE" },
);
Manual Transaction Control
Start, commit, and rollback transactions manually:
const trx = await sql.startTransaction();
await User.insert({ ...data }, { trx });
await trx.commit();
Rollback on error:
const trx = await sql.startTransaction();
try {
await User.insert({ ...data }, { trx });
throw new Error("fail");
await trx.commit();
} catch {
await trx.rollback();
}
Nested Transactions (Savepoints)
Nested transactions are implemented using database savepoints on the same connection as the outer transaction (no new connections are opened). This enables partial rollbacks without affecting the outer scope.
- No new connections: nested transactions reuse the outer transaction's connection
- Commit: releases the savepoint (does not commit the outer transaction)
- Rollback: rolls back to the savepoint (does not roll back the outer transaction)
Savepoint names are stable and driver-safe: sp_<nestingDepth>_<transactionIdPrefix>
(for example: sp_2_AB12CD34
).
const outerTrx = await sql.startTransaction();
await User.insert({ ...data }, { trx: outerTrx });
// Creates a savepoint on the same connection
const innerTrx = await outerTrx.nestedTransaction();
try {
await User.insert({ ...data }, { trx: innerTrx });
await innerTrx.commit(); // RELEASE SAVEPOINT <name>
} catch (e) {
await innerTrx.rollback(); // ROLLBACK TO (savepoint)
throw e;
}
await outerTrx.commit(); // commits the top-level transaction and releases the connection
Concurrent Transactions
You can run multiple transactions in parallel on different connections:
const trx1 = await sql.startTransaction();
const trx2 = await sql.startTransaction();
await User.insert({ ...data }, { trx: trx1 });
await User.insert({ ...data }, { trx: trx2 });
await trx1.commit();
await trx2.commit();
Global Transactions
For integration tests, you can use global transactions. Global transactions are not advised for production use.
await sql.startGlobalTransaction();
// Automatically uses the transaction from the sql global transaction
await User.insert({ ...data });
await sql.commitGlobalTransaction();
Rollback global transaction:
await SqlDataSource.startGlobalTransaction();
await User.insert({ ...data });
await sql.rollbackGlobalTransaction();
Error Handling and Transaction State
You can enforce error throwing if a transaction is inactive:
const trx = await sql.startTransaction();
await trx.rollback();
await trx.rollback({ throwErrorOnInactiveTransaction: true }); // Throws HysteriaError
Or suppress errors:
const trx = await sql.startTransaction();
await trx.rollback();
await trx.rollback({ throwErrorOnInactiveTransaction: false }); // No error
Notes
- Nested transactions never release the connection but only save points; only the top-level transaction releases it on commit/rollback.
- Always pass the
trx
object to model methods to ensure operations are part of the transaction. - Use isolation levels for advanced consistency requirements.
See also: