AWS Certified Developer - Associate (DVA-C02) #4 Domain 1-3 Development with AWS Services — DynamoDB Development
Now that we’ve covered the gateway in #3 API Gateway, it’s time for the data behind it. The default database for serverless applications is DynamoDB. Where the SAA exam asks “when do you choose DynamoDB?”, DVA goes one level deeper and asks, at the code level, “how do you design the keys, how do you prevent write conflicts, and how do you stream changes out?”
Key design — partition key and sort key #
Every DynamoDB table identifies items by a primary key.
| Key composition | Meaning |
|---|---|
| Partition key only | The partition key value is the item’s unique identifier |
| Partition key + sort key | Within the same partition key, the sort key sorts and range-queries multiple items |
The partition key is the basis on which data is physically distributed. If traffic concentrates on one key (a hot partition), only that partition is throttled. That’s why the exam regards “a partition key that distributes evenly” as good design. You should choose an attribute with high cardinality and even access as the partition key.
Query vs Scan #
- Query — finds items by partition key and narrows the range by sort key. Efficient.
- Scan — reads the entire table. Slow and expensive.
Exam principle: avoid Scan and use Query. If “I need to query frequently by a specific attribute, but it’s not a key,” the answer is not Scan but an index (GSI).
LSI vs GSI #
To query by a non-key attribute, you need a secondary index. The difference between the two kinds is an exam regular.
| Aspect | LSI (Local Secondary Index) | GSI (Global Secondary Index) |
|---|---|---|
| Partition key | Same as the table | Can be a different attribute |
| Sort key | A different attribute | A different attribute |
| Creation time | Only at table creation | Add/remove anytime |
| Consistency | Strong consistency possible | Eventually consistent only |
| Capacity | Shares table capacity | Own capacity |
The one-liner: LSI is only at table creation, same partition key. GSI is anytime, different partition key. Most “query by a different attribute” requirements are answered by the flexible GSI. Consider an LSI only when you need a different sort key within the same partition key and require strong consistency.
Read consistency #
DynamoDB reads offer two consistency levels.
- Eventually consistent read (default) — the most recent write may not yet be reflected. Half the cost.
- Strongly consistent read — always the latest value. Twice the cost, and not available on a GSI.
Capacity modes and throttling #
| Mode | When it fits |
|---|---|
| On-Demand | Traffic is unpredictable/intermittent. No capacity management |
| Provisioned | Traffic is predictable. Pre-specify RCU/WCU, Auto Scaling available |
In provisioned mode, exceeding capacity raises a ProvisionedThroughputExceededException (throttling). The SDK automatically retries with exponential backoff by default. Short momentary bursts are partially absorbed by adaptive capacity. The answer to “it’s throttling” is usually raise capacity, improve key distribution, and retry with exponential backoff.
Conditional writes and optimistic locking #
This is the most important development pattern in DVA. A conditional write performs the write only when a condition is true.
- Create only if the item doesn’t exist — use the
attribute_not_exists(PK)condition to prevent duplicate creation (used for idempotency). - Optimistic locking — put a
versionattribute on the item and write with the condition “only when it matches the version I read.” If two clients modify the same item at once, only one succeeds and the other receives aConditionalCheckFailedExceptionand retries.
UpdateItem
SET stock = stock - 1, version = version + 1
ConditionExpression: version = :expectedVersion- Atomic counter — increment unconditionally, as in
SET views = views + 1. Suitable for simple counts where conflict checking isn’t needed.
Optimistic locking = conditional write + version attribute. It’s the correct answer for questions about handling concurrent-modification conflicts.
DynamoDB Streams #
A change log that captures item changes (create, update, delete) in time order.
- Connect Lambda via an event source mapping to react to changes (e.g., send a notification when a new order arrives).
- Stream records can carry before/after images (
StreamViewType). - It’s also the foundation of global tables (multi-region replication).
The answer to “automatically run follow-up processing when an item is added to DynamoDB” is Streams + Lambda.
TTL #
When you set an expiration time (epoch) attribute on an item, DynamoDB automatically deletes expired items. It’s used for cleaning up sessions and temporary data, and the deletion isn’t immediate but happens in the background (usually within 48 hours). TTL deletions are also captured by Streams.
DAX #
DynamoDB Accelerator (DAX) is an in-memory cache built specifically for DynamoDB, lowering read responses to the microsecond level.
- Suitable for read-heavy, latency-sensitive workloads.
- Almost no application code changes (swap in the DAX client).
- The trap is distinguishing it from a general-purpose cache (ElastiCache). “DynamoDB reads in microseconds” is DAX; “a general-purpose in-memory cache” is ElastiCache.
Exam question patterns #
- “I need to query frequently by a non-key attribute.” → GSI (not Scan).
- “I want to add an index after creating the table.” → GSI (LSI is only at creation).
- “Two users modify the same item at once. How do I prevent conflicts?” → Conditional write + version (optimistic locking).
- “I want to create only once even if the same order comes in twice.” →
attribute_not_existsconditional write. - “Run follow-up work automatically when an item is added.” → DynamoDB Streams + Lambda.
- “A
ProvisionedThroughputExceededExceptionoccurs.” → Raise capacity, distribute keys, exponential backoff. - “DynamoDB read latency in microseconds.” → DAX.
- “Auto-delete session data after a certain time.” → TTL.
Wrap-up #
What this post locked in:
- The partition key is the distribution basis. Even distribution = a good key. Query, not Scan
- LSI (at creation, same partition key, strong consistency) vs GSI (anytime, different partition key, own capacity, eventual consistency)
- Conditional write + version = optimistic locking;
attribute_not_existsis idempotent creation - React to changes with Streams + Lambda, auto-expire with TTL
- Handle throttling with capacity, key distribution, and exponential backoff; handle read latency with DAX
Next — Domain 1-4 Messaging and Events #
Serverless scales by loosely connecting components with asynchronous messaging. In #5 Messaging and Events, I’ll cover SQS (standard vs FIFO), SNS, fan-out combining the two, EventBridge’s event routing, and Step Functions’ workflow orchestration.