Connect transaction-level read concern, write concern, primary read preference, snapshot visibility, and retry labels to observable behavior on a replica set.

Read Concern, Write Concern, Retry Semantics, and Snapshot Behavior Inside Transactions

Separate read concern, write concern, and primary routing; then prove snapshot visibility while another client commits a newer value.

Intermediate110–160 minutesThree-member snapshot/majority labMongoDB 8.3.8 · mongosh 2.10.0 · PyMongo 4.17.0Last reviewed: September 2026

Learning objectives

01

Separate read concern, write concern, and read preference instead of treating them as one consistency switch.

02

Prove repeatable snapshot visibility inside a transaction while another client commits a newer value.

03

Explain why snapshot and majority guarantees inside transactions depend on a successful w:"majority" commit.

04

State why transaction reads must route to the primary.

05

Connect TransientTransactionError and UnknownTransactionCommitResult to different retry scopes.

Reproducible lab baseline

This lesson pins MongoDB Community Server 8.3.8 with mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim, mongosh 2.10.0, and PyMongo 4.17.0 where a driver example is used. Transactions require a replica set or sharded cluster, so the mandatory local lab runs a disposable replica set published only on loopback beginning at 127.0.0.1:27079. Authentication and TLS are disabled only for this isolated learning topology. Feature Compatibility Version (FCV) is observed and never changed. Unless a section explicitly overrides them, read/write concern and read preference use the transaction/client defaults described beside the example. Atlas, Search, Vector Search, KMS, and Enterprise Advanced are not mandatory. This lesson uses a three-member replica set so w:"majority" represents acknowledgement by an actual voting majority. The client connects directly to the designated primary for a deterministic local lab; that direct connection is not a production failover configuration. The product commands were not executed in this generation environment because Docker, mongod, mongosh, and PyMongo are unavailable here; measured output must be recorded on the learner's machine.

1. Three different controls: visibility, acknowledgement, and routing

Read concern controls the consistency/isolation properties of reads. Transactions support local, majority, and snapshot. Write concern controls acknowledgement at transaction commit; individual write statements inside a transaction must not specify their own write concern. Read preference controls which replica-set member serves reads; transactions that contain reads must use primary.

The terms are related but not interchangeable. A transaction using read concern snapshot obtains its documented majority-committed snapshot guarantee only when it commits with write concern majority. On sharded clusters, snapshot is the transaction read concern that synchronizes the snapshot across shards.

bash · three-member replica-set setup for Lesson 3
docker network rm atlasmart-ch13-l3-net 2>/dev/null || truedocker rm -f atlasmart-ch13-l3-n1 2>/dev/null || truedocker volume rm atlasmart-ch13-l3-n1-data 2>/dev/null || truedocker rm -f atlasmart-ch13-l3-n2 2>/dev/null || truedocker volume rm atlasmart-ch13-l3-n2-data 2>/dev/null || truedocker rm -f atlasmart-ch13-l3-n3 2>/dev/null || truedocker volume rm atlasmart-ch13-l3-n3-data 2>/dev/null || truedocker network create atlasmart-ch13-l3-netdocker run -d --name atlasmart-ch13-l3-n1 --network atlasmart-ch13-l3-net -p 127.0.0.1:27079:27017 -v atlasmart-ch13-l3-n1-data:/data/db mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim --replSet atlasmart-rs13-l3 --bind_ip_alldocker run -d --name atlasmart-ch13-l3-n2 --network atlasmart-ch13-l3-net -p 127.0.0.1:27080:27017 -v atlasmart-ch13-l3-n2-data:/data/db mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim --replSet atlasmart-rs13-l3 --bind_ip_alldocker run -d --name atlasmart-ch13-l3-n3 --network atlasmart-ch13-l3-net -p 127.0.0.1:27081:27017 -v atlasmart-ch13-l3-n3-data:/data/db mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim --replSet atlasmart-rs13-l3 --bind_ip_alluntil mongosh "mongodb://127.0.0.1:27079/admin?directConnection=true" --quiet --eval 'quit(db.runCommand({ping:1}).ok === 1 ? 0 : 1)'; do sleep 1; donemongosh "mongodb://127.0.0.1:27079/admin?directConnection=true" --quiet --eval 'rs.initiate({_id:"atlasmart-rs13-l3",members:[{_id:0,host:"atlasmart-ch13-l3-n1:27017",priority:2},{_id:1,host:"atlasmart-ch13-l3-n2:27017"},{_id:2,host:"atlasmart-ch13-l3-n3:27017"}]})' until mongosh "mongodb://127.0.0.1:27079/admin?directConnection=true&replicaSet=atlasmart-rs13-l3" --quiet --eval 'quit(db.hello().isWritablePrimary ? 0 : 1)'; do sleep 1; doneuntil mongosh "mongodb://127.0.0.1:27079/admin?directConnection=true&replicaSet=atlasmart-rs13-l3" --quiet --eval 'const m=rs.status().members; quit(m.filter(x=>x.stateStr==="SECONDARY").length===2 ? 0 : 1)'; do sleep 1; donemongosh "mongodb://127.0.0.1:27079/admin?directConnection=true&replicaSet=atlasmart-rs13-l3" --quiet --eval 'printjson({server:db.version(),setName:db.hello().setName,states:rs.status().members.map(m=>({name:m.name,state:m.stateStr}))}); printjson(db.runCommand({getParameter:1,featureCompatibilityVersion:1}))' 

2. Seed one account and inspect defaults/topology

javascript · seed account plus observe concern/topology context
const c=db.accounts_ch13_l3;c.drop();c.insertOne({_id:"acct-1",tenantId:"tenant-a",balanceCents:5000,version:1});printjson(c.findOne({_id:"acct-1"}));printjson(db.getSiblingDB("admin").runCommand({getDefaultRWConcern:1}));printjson(db.hello());print("transaction rules:");print("read concerns: local | majority | snapshot");print("transaction reads must use primary read preference");print("transaction write concern is applied at commit, not per statement");

The three-node lab is still not a production durability benchmark: all members run on one host and likely one physical failure domain. It only makes the acknowledgement mechanism observable.

3. Prove snapshot behavior with two clients

The reader starts a transaction using snapshot. After its first read establishes the transaction snapshot, a second client increments the account outside that transaction. The second read inside the transaction should return the same pre-update value as the first read. After the read-only transaction commits, an ordinary outside read sees the newer committed value.

python · two-client snapshot visibility experiment
from pymongo import MongoClientfrom pymongo.read_concern import ReadConcernfrom pymongo.write_concern import WriteConcernfrom pymongo.read_preferences import ReadPreferenceuri = "mongodb://127.0.0.1:27079/?directConnection=true&replicaSet=atlasmart-rs13-l3"reader = MongoClient(uri)writer = MongoClient(uri)coll_r = reader.atlasmart.accounts_ch13_l3coll_w = writer.atlasmart.accounts_ch13_l3with reader.start_session() as session:    session.start_transaction(        read_concern=ReadConcern("snapshot"),        write_concern=WriteConcern("majority"),        read_preference=ReadPreference.PRIMARY,    )    first = coll_r.find_one({"_id": "acct-1"}, session=session)    outside = coll_w.update_one(        {"_id": "acct-1"},        {"$inc": {"balanceCents": 700, "version": 1}},    )    second = coll_r.find_one({"_id": "acct-1"}, session=session)    print({"first": first, "outside_modified": outside.modified_count, "second": second})    session.commit_transaction()print({"after_commit_outside": coll_w.find_one({"_id": "acct-1"})})reader.close(); writer.close()
What this proves—and does not prove

Matching first and second values demonstrates snapshot visibility for this transaction. The final outside value demonstrates that a newer committed version existed concurrently. This lab does not prove geographic durability, cross-shard behavior, or failover recovery because all replica-set members are local.

4. Retry labels map to different uncertainty

Signal Meaning for retry scope Application consequence
TransientTransactionError The transaction as a whole can be retried. The body may execute again; external side effects must be idempotent/deduplicated.
UnknownTransactionCommitResult The client cannot determine the commit result. Retry commit; do not assume the transaction failed.
TransactionTooLargeForCache Large transaction/caching pressure failure; server behavior changed in 6.2. Do not expect callback retry to make an oversized transaction safe; shrink/redesign it.

The driver callback API incorporates the standard retry rules. A lower-level/core API gives you more control but makes you responsible for correctly inspecting error labels.

5. Production judgment

Use snapshot when one transaction must reason over a stable multi-document view; do not enable it reflexively for every request. Long snapshots retain older versions and can increase storage/cache pressure. Pair the read guarantee with a commit write concern that provides the durability property you actually intend. A w:1 commit can be rolled back during failover and does not give the same guarantees to transaction-level majority/snapshot reads.

On a sharded cluster, majority read concern does not synchronize one snapshot across shards; snapshot does. Even after a multi-shard commit, some outside reads with weaker concerns need not wait for all shards to expose the transaction simultaneously. Record topology and concern settings beside every consistency claim.

Bridge. Lesson 4 asks how long a transaction may run, how it waits for locks, what operations are restricted, and how multi-shard coordination expands the failure surface.

bash · cleanup / full reset
docker rm -f atlasmart-ch13-l3-n1docker rm -f atlasmart-ch13-l3-n2docker rm -f atlasmart-ch13-l3-n3docker volume rm atlasmart-ch13-l3-n1-datadocker volume rm atlasmart-ch13-l3-n2-datadocker volume rm atlasmart-ch13-l3-n3-datadocker network rm atlasmart-ch13-l3-net

Check your understanding

  1. Which transaction read concern synchronizes a snapshot across shards?
  2. Can individual writes inside a transaction set their own write concern?
  3. What read preference must a transaction with reads use?
  4. Why can an in-transaction read be stale relative to a newer outside commit?
  5. Why is w:"majority" important with transaction snapshot?
Review the answers

1. snapshot.

2. No. Transaction write concern is applied at commit; per-operation write concern inside a transaction is not the model.

3. primary.

4. The transaction can continue reading from its established snapshot.

5. The documented majority-committed snapshot guarantee depends on committing the transaction with majority write concern.

Authoritative references

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 Ethereum or ERC-20 compatible assets to this address.