Transactions¶
NSQLite supports SQLite transactions over the RPC API. A transaction lets you group multiple writes atomically: either all succeed or all are rolled back.
Lifecycle¶
A transaction follows four steps:
- BEGIN — Start a transaction and get a transaction ID (
txId) - Execute queries — Run read/write queries with the
txId - COMMIT — Persist all changes
- ROLLBACK — Discard all changes (instead of COMMIT)
┌───────┐
│ BEGIN │──→ returns txId
└───┬───┘
│
▼
┌──────────┐
│ Query 1 │── uses txId
└──────────┘
│
▼
┌──────────┐
│ Query 2 │── uses txId
└──────────┘
│
├──────────────┐
▼ ▼
┌────────┐ ┌──────────┐
│ COMMIT │ │ ROLLBACK │── uses txId
└────────┘ └──────────┘
Starting a Transaction¶
Send a BEGIN TRANSACTION query. The response includes a txId that you use in subsequent queries.
curl -X POST http://localhost:9876/rpc/Database/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer my-token" \
-d '{"queries": [{"query": "BEGIN TRANSACTION"}]}'
Response:
{
"ok": true,
"output": {
"time": 0.002,
"results": [
{
"type": "begin",
"time": 0.002,
"txId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
]
}
}
The txId is a UUID that identifies your transaction session.
Executing Queries Within a Transaction¶
Pass the txId in each query you want to execute inside the transaction.
curl -X POST http://localhost:9876/rpc/Database/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer my-token" \
-d '{
"queries": [
{
"query": "INSERT INTO users(name) VALUES(?)",
"params": [{"value": {"text": "fiona"}}],
"txId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
{
"query": "UPDATE accounts SET balance = balance - 100 WHERE user_id = 1",
"txId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
]
}'
All queries in a transaction execute on the single read-write connection and are serialized.
Committing¶
curl -X POST http://localhost:9876/rpc/Database/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer my-token" \
-d '{"queries": [{"query": "COMMIT", "txId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}]}'
Response:
Rolling Back¶
curl -X POST http://localhost:9876/rpc/Database/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer my-token" \
-d '{"queries": [{"query": "ROLLBACK", "txId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}]}'
Idle Timeout¶
If a transaction has no activity within the configured idle window, it is automatically rolled back by the server.
| Variable | Default | Description |
|---|---|---|
NSQLITE_TX_IDLE_TIMEOUT |
10s |
Maximum idle time before auto-rollback |
Set this to a longer duration for long-running transactional workflows:
Valid time units: ns, us, µs, ms, s, m, h.
When a transaction times out, subsequent queries with the old txId receive:
{
"ok": true,
"output": {
"results": [
{
"type": "error",
"time": 0.001,
"error": "transaction not found or timed out, check your settings"
}
]
}
}
Concurrency Model¶
NSQLite manages concurrency through two locks:
| Lock | Scope | Purpose |
|---|---|---|
txMu |
Transaction | Ensures only one transaction runs at a time |
writeMu |
Write query | Ensures write queries are serialized |
- Only one transaction can be active at any time. Other clients that attempt
BEGINwill queue until the current transaction finishes (COMMIT or ROLLBACK) or times out. - Read queries outside a transaction can run in parallel across multiple read-only connections.
- While a transaction is open, all queries (including reads) within it go through the single read-write connection.
Error Messages¶
| Error | Meaning |
|---|---|
transaction not found or timed out, check your settings |
The txId is invalid, already completed, or timed out |
transaction ID does not match the currently active transaction |
The txId does not match the open transaction |
cannot start a transaction within a transaction |
Called BEGIN while a transaction is already open |
transaction ID is required for this operation |
Used COMMIT, ROLLBACK, or END without a txId |
Best Practices¶
- Always use a
txIdwith COMMIT and ROLLBACK queries. The server needs it to identify which transaction to finalize. - Keep transactions short. Idle transactions block other writers.
- Always COMMIT or ROLLBACK. Unclosed transactions hold resources and block other clients until the idle timeout fires.
- Include the
txIdon every query inside the transaction. Read queries without atxIdexecute outside the transaction on the read pool and if they are write operations, they wait until the active transaction finishes.