Transaction Semantics Reference
Overview
This page focuses on the current behavioral semantics of the Juice transaction APIs so that you can choose the right pattern in the service layer.
Terminology:
Manual transaction:
engine.Tx()orengine.ContextTx(...)with explicitBegin/Commit/Rollback.Functional transaction:
juice.Transaction(...)orjuice.NestedTransaction(...).Current transaction context: the manager in
ctxis already aTxManager.
Semantics Matrix
API |
Start condition |
Behavior on success |
Behavior on failure |
Typical scenario |
|---|---|---|---|---|
|
|
Commits after explicit |
Rolls back after explicit |
Infrastructure-level code that needs fine-grained control |
|
Same as above, but accepts |
Same as above |
Same as above |
Transactions with a specific isolation level or read-only flag |
|
|
Commits when |
Rolls back when |
A unified transaction boundary in the service layer |
|
Reuses the current transaction if one exists, otherwise opens a new one |
When reusing, the outer transaction commits; otherwise it follows |
When reusing, the error bubbles to the outer layer; otherwise it rolls back |
Composed services that should not repeatedly open transactions |
Behavior Details
1) Context requirements for ``Transaction``
juice.Transaction extracts the manager from ctx and requires it to be a *juice.Engine. Otherwise it returns an error.
Common mistakes:
The manager was not injected into
ctxwithjuice.ContextWithManager.A context that is already inside a transaction is passed back into
Transactiondirectly. In that case the manager is usually not a*juice.Engine.
Recommendation:
Use
Transactionat the outer entry point.Use
NestedTransactionfor reuse in inner layers.
2) ``NestedTransaction`` is not a savepoint
The semantics of NestedTransaction are “join when a transaction exists, create one otherwise”. It is not a database SAVEPOINT abstraction.
That means:
Reusing an outer transaction does not create an independent inner commit point.
An inner failure affects whether the outer transaction can commit, and should usually be returned upward.
3) Special error ``tx.ErrCommitOnSpecific``
When handler returns tx.ErrCommitOnSpecific, the transaction still attempts to commit and returns that error together with any commit error.
This is intended for special cases where a specific commit path must be marked explicitly. It is usually not something normal business code should depend on.
How to Choose in Practice
Choose manual transactions when you need full lifecycle control.
Prefer functional transactions when a business function is the transaction boundary.
When service A calls service B and both may also be called independently, use outer
Transactionplus innerNestedTransaction.If you need savepoint-level semantics, wrap them explicitly on the business side according to your database capabilities.