A database transaction can make a group of changes atomic inside the database that runs it. It does not automatically include a payment provider, email service, or message broker. To handle the gap between committing business data and publishing an event, write the event to a transactional outbox in the same database transaction, then relay it and make consumers safe to run more than once.
What does a database transaction actually guarantee?
A transaction groups database operations into a unit: if it commits, the database applies the unit; if it fails and rolls back, its changes do not take effect. PostgreSQL’s documentation describes the visibility guarantee this way: “A transaction is said to be atomic: from the point of view of other transactions, it either happens completely or not at all.” PostgreSQL’s transaction tutorial illustrates this with a bank transfer: the debit and credit should succeed together, rather than leave a partial transfer visible.
As an Amazon Associate I earn from qualifying purchases.
The boundary matters. This guarantee applies to work managed by the participating database transaction. Rolling back database changes does not retract an email already sent, undo a payment already accepted by an independent provider, or make a broker forget a published message. Those systems are outside the local transaction unless a distributed coordination mechanism explicitly enlists them and supports the needed semantics.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Does ACID mean the business operation is automatically safe?
No. ACID describes properties of transaction processing; it does not know which business rules your application needs. Your code and database schema must express invariants—for example, that an account balance cannot become invalid—and the transaction must use isolation and database behavior appropriate to those rules.
#1 Best Overall
Isolation mechanisms differ, and stronger protections can involve locks or other resource use. Microsoft’s SQL Server transaction locking and row versioning guide explains how isolation, locking, and row versioning affect concurrency. Keep transactions short where possible: holding resources for longer can increase contention.
Durability also depends on engine configuration. For example, SQL Server’s transaction durability documentation distinguishes full durability, which waits for log persistence before reporting a successful commit, from delayed durability, which can acknowledge before the log is flushed. That is a SQL Server option, not a rule that describes every database. MongoDB likewise cautions that distributed transactions can cost more than single-document writes and should not replace effective schema design; see its transaction manual.
Are external API calls part of a database transaction?
Usually, no. A normal HTTP call, email send, or broker publish is not undone when a local database transaction rolls back. Putting such a call inside transaction-handling code does not make the external system a participant in the database commit.
External effects also interact badly with retries. Google Cloud’s Spanner transaction overview warns that a retried transaction can repeat side effects involving systems or state outside Spanner. If a retryable transaction body charges a card or sends a notification directly, the external action may happen more than once even if the database ultimately commits only once. Keep non-idempotent external actions out of retryable transaction bodies where possible.
Rank #3
Why is updating a database and publishing a message a dual-write problem?
Consider an application that updates an order in its database and publishes an “order placed” event to a broker as two separate actions. Neither ordering makes both actions atomic:
- Publish before commit: the broker may deliver the event, then the database transaction may roll back. A consumer is told about a change that never committed.
- Commit before publish: the database may commit, then the application may crash before publishing. The business state exists, but downstream systems never receive its event.
These are the failure windows described by the transactional outbox pattern. A local transaction cannot close them by itself because the broker and database are separate systems.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How do you atomically update a database and publish a message?
Use a transactional outbox when the business update and event must not get out of sync. In one transaction, write the business changes and an outbox record representing the event to the same database. A separate relay reads committed outbox records and publishes them. The atomic guarantee is that the business change and the intent to publish commit together; the broker is not part of that commit.
Recommended Free Tools
- Begin a database transaction.
- Apply the business-state changes, such as marking an order as placed.
- Insert an outbox record containing the event data and a stable message identifier.
- Commit. If the transaction rolls back, neither the business changes nor the outbox record is committed.
- Run a relay that finds committed outbox records, publishes them, and records or otherwise tracks progress.
- Make each consumer handle duplicate message identifiers safely, ideally recording the identifier in the same transaction as its own business update.
This pattern removes the failure window where committed database state has no durable record of the message to publish. It does not guarantee one-and-only-one delivery: a relay can publish successfully and crash before recording progress, then publish the same record again after restarting. Consumers therefore need idempotent handling. The idempotent consumer pattern describes recording message identifiers so duplicates can be rejected safely.
Which outbox relay approach should you use?
| Approach | How it works | Trade-offs |
|---|---|---|
| Polling publisher | A relay repeatedly queries pending outbox rows and publishes them. | The pattern reference says polling works with SQL databases; event ordering can be difficult. Polling publisher |
| Transaction-log tailing or change data capture | A relay reads committed changes from the database log or an equivalent change stream. | It relies on database-specific mechanisms, and duplicate publishing remains a concern. Examples in the pattern reference include PostgreSQL WAL, MySQL binlog, and DynamoDB streams. Transaction log tailing |
Choose based on the database and operational setup you can support, as well as ordering requirements. Neither relay removes the need for idempotent consumers. If event order matters, define how records are ordered and how the relay preserves that order for the relevant entity; do not assume a generic outbox automatically provides every ordering guarantee.
Quick Recap
What to verify before relying on a transaction
- Scope: identify exactly which database or resource managers participate in the commit. Treat external systems as outside the boundary unless a supported distributed transaction mechanism coordinates them.
- Invariant and isolation: state the business rule the transaction must preserve, then confirm the chosen isolation and database behavior protect it under concurrent work.
- Durability configuration: check what a successful commit means for the specific engine and settings in use.
- Retry behavior: assume retryable transaction code can run again. Avoid direct non-idempotent side effects in that code.
- Message handling: persist publication intent with business state, expect relay duplicates, and make consumers idempotent.
- Operations: monitor pending outbox records and relay failures, and define how stuck or repeatedly failing records are investigated and retried.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




