Chapter 10 · Transaction Boundaries and Consistency by Design

Modeling Business Transactions

Model business operations as explicit transactions, identify their boundaries, and preserve invariants across all writes that belong to one logical unit of work.

Beginner65–90 minutesTransaction modeling + workflow designLast reviewed: August 2026

Learning outcomes

A database transaction should correspond to a meaningful unit of business work—not merely to “whatever SQL statements happen to run together.” Good transaction boundaries protect invariants, simplify failure handling, and make concurrency behavior understandable.

01

Define business transactions before writing SQL transactions.

02

Identify which writes must succeed or fail together.

03

Separate transactional state changes from side effects that cannot participate in the same database transaction.

04

Design WorkshopHub operations with explicit transaction boundaries.

Business transaction versus database transaction

A business transaction is a logical operation such as “assign a technician,” “close a work order,” or “record part usage.” A database transaction is the DBMS mechanism used to make a group of database changes atomic and isolated.

Ideally, one database transaction protects one business operation whose invariants must hold together.

WorkshopHub example: assign a technician

The operation may need to:

  1. verify the WorkOrder exists and is assignable;
  2. verify the Technician is active;
  3. ensure no conflicting primary assignment exists;
  4. insert WorkOrderAssignment;
  5. write an audit/status event.

If step 4 succeeds but step 5 fails, should the assignment remain? The answer defines the transaction boundary.

Atomic unit of work

sql · example
BEGIN;-- validate state-- insert assignment-- update work-order status if needed-- insert audit/status historyCOMMIT;

If any required step fails, rollback the entire unit.

Boundary rule

Put together the changes that must be simultaneously true for the business operation to be valid.

Do not make transactions too small

If each statement commits independently:

sql · example
INSERT assignment; COMMIT;UPDATE work_order; COMMIT;INSERT audit_event; COMMIT;

failure between statements can leave partial state.

Do not make transactions unnecessarily large

A transaction that remains open while waiting for a user, external API, or long computation can hold locks, increase contention, and raise rollback cost.

Keep external calls out of critical DB transactions when possible

Suppose closing a WorkOrder must send an email. Email cannot roll back with the database. A safer structure is:

  1. commit the database state change;
  2. record an outbound event/task in the same transaction;
  3. deliver the email asynchronously;
  4. retry delivery independently.

The outbox pattern

sql · example
BEGIN;UPDATE work_orderSET status_code = 'closed'WHERE work_order_id = ?;INSERT INTO outbox_event(...)VALUES (..., 'WorkOrderClosed', ...);COMMIT;

A background worker publishes the outbox event. Because state change and event creation commit together, the system avoids “database committed but message lost.”

Read-modify-write transactions

Many business operations follow:

model · example
read current statevalidate rulecompute new statewrite new state

This pattern is concurrency-sensitive because another transaction may change the row between read and write. Later lessons examine isolation and locking.

Model transactions from commands

Useful domain commands include:

  • OpenWorkOrder;
  • AssignTechnician;
  • RecordPartUsage;
  • CompleteAssignment;
  • CloseWorkOrder;
  • TransferAssetOwnership.

Each command suggests a transaction boundary and invariant set.

CloseWorkOrder invariants

Before closing, WorkshopHub may require:

  • WorkOrder is currently open/in-progress;
  • no active assignments remain;
  • required tasks are complete;
  • all parts used are recorded;
  • closed_at is set;
  • status history records the transition.

Transaction boundary diagram

Transaction ownership

A transaction should usually be owned by the service/application operation that understands the full invariant. Repository methods that commit independently can make multi-step business transactions impossible.

Nested application operations

If CloseWorkOrder calls helpers, those helpers should join the existing transaction rather than starting and committing unrelated ones.

Batch operations

“Import 100,000 parts” may not belong in one giant transaction. Ask whether the business requires all 100,000 to appear atomically. Often chunked transactions with idempotent import keys are safer.

Human workflows are not one long transaction

A repair process lasting three days cannot be represented by keeping one DB transaction open for three days. Instead model persistent states and short transactions between those states.

Practice: define the boundary

Record part usage

The operation must insert PartUsage, decrement inventory, verify sufficient stock, and record an audit event. Which actions belong in one transaction?

Review answer

The stock check, inventory decrement, PartUsage insert, and audit record should normally commit together because partial success would violate business state. External notifications can be placed behind an outbox or another post-commit mechanism.

Summary and next lesson

Transaction design starts from business commands and invariants. Group the changes that must be true together, keep external side effects out of the critical commit path, and model long workflows as durable states rather than long-lived transactions. The next lesson examines ACID as the formal foundation beneath these choices.

References

  • Jim Gray and Andreas Reuter, Transaction Processing: Concepts and Techniques.
  • Martin Kleppmann, Designing Data-Intensive Applications.
  • PostgreSQL documentation on transactions.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only assets compatible with the Ethereum/ERC-20 network. Do not send TRC-20/TRON assets.