A modern Java system does not need one storage technology for everything.
Some data needs ACID transactions. Some data needs a fast key-based lookup. Some data is flexible and document-shaped. Some data moves in huge files between legacy systems. Trying to force all of those use cases into one storage engine usually creates a system that is slower, harder to maintain, and harder to scale.
A multi-tier storage strategy means choosing the right storage model for each part of the architecture.
The Problem
Older application designs often started by choosing one persistence platform. The team selected a relational database or another enterprise storage system, then shaped the application around it.
That approach can still work for simple applications, but modern systems often have different data access patterns inside the same product.
A mobile payment platform might need:
- Strong consistency for payment records.
- Fast session access for mobile users.
- Flexible documents for changing customer metadata.
- Large file exchange with legacy batch systems.
- Middleware journals for durable message processing.
- Search or reporting views optimized for a different access pattern.
One storage model rarely handles all of that cleanly.
One-size storage:
All data -> one database
Multi-tier storage:
Payment records -> relational database
Sessions -> key value store
Flexible profiles -> document store
Batch exchange -> filesystem or object storage
The architecture becomes clearer when each storage choice has a purpose.
Core Idea
The chapter points to a modern direction: each microservice should own its own data, and each service can choose the persistence technology that best matches its business domain and access pattern.
This is not only for microservices. Even in less innovative architectures, it is worth evaluating multiple storage ideas instead of defaulting everything to one database.
The practical rule is:
Choose storage by use case:
structure, consistency, access pattern, volume, durability, and integration need
That means storage selection is part of architecture design, not an implementation detail left until the end.
Relational Databases for Structured Transactional Data
Relational databases are a strong choice when data is structured upfront, and the structure does not change constantly.
They are also the best fit when the application needs ACID-compliant transactions.
In a payment system, the payment record is a strong candidate for relational storage.
Payment service
|
v
Relational database
Why:
- stable data structure
- clear identifiers
- relationships to users and accounts
- strong consistency requirement
- transactional updates
The relational database should store the data that must be protected by strict consistency rules. It does not need to store every temporary value in the system.
Key Value Stores for Sessions and Database Offloading
Key-value stores are especially useful in memory-focused setups.
The chapter gives two common scenarios: user sessions and database offloading.
Session data often needs high performance because web and mobile applications interact with it frequently. In the worst case, losing a session may log the user out, which is unpleasant but often less severe than corrupting payment data.
Mobile user
|
v
API service
|
v
Session key value store
Database offloading means placing a cache in front of slower storage. Read-through, write-through, read-behind, write-behind, and related patterns can reduce database load and improve response time.
API service
|
v
Cache
|
v
Relational database
The important warning is that cached data can become stale. The team must define how fresh the data must be and how changes propagate.
NoSQL for Flexible or Specialized Data
NoSQL databases should be selected for scenarios suited to their specific model.
Document repositories are useful when entities have variable or unstructured representations. For example, a customer profile extension or metadata payload may change often and may not fit a fixed table shape.
{
"customerId": "cust-123",
"preferences": {
"language": "en",
"preferredChannel": "mobile"
},
"extraAttributes": {
"campaign": "summer"
}
}
Graph databases are useful when graph algorithms or relationship traversal matter. The chapter mentions shortest path calculation as an example of a graph-oriented use case.
Wide-column and key value approaches cover other distributed data patterns.
Do not choose NoSQL as a replacement for transactionality. Choose it when the data shape or access pattern benefits from the chosen category.
Filesystem and Object Storage for Large Data Exchange
Filesystem storage is fundamental infrastructure. Applications and middleware may need it even when the main business data lives elsewhere.
The chapter highlights several important filesystem concepts:
- Filesystems can provide journaling to reduce corruption risk.
- Locking can provide exclusive access.
- Local filesystems include examples such as NTFS and ext.
- Networked filesystems allow access across systems.
- NFS, FTP, and SFTP are common networked file access approaches.
- Amazon S3 is described as object filesystem-style storage accessed through APIs, and S3-compatible storage exists in several environments.
Filesystems are especially practical for large data exchange.
Payment batch export
|
v
CSV file
|
v
Signed and chunked transfer
|
v
Legacy processing system
This is common in legacy-heavy environments such as banking, where large batches of operations may move as files.
The weakness is search and concurrency. Filesystems do not usually provide native indexing or full-text search. Networked filesystems can also perform poorly with concurrent access and file locking.
Example Storage Map
A practical payment platform could deliberately use several storage technologies.
Payment transaction service
-> relational database
reason: ACID and structured records
Session service
-> key value store
reason: low-latency lookup by session ID
Customer profile extension
-> document repository
reason: flexible profile attributes
Relationship analytics
-> graph repository
reason: relationship traversal and graph algorithms
Legacy settlement export
-> filesystem or object storage
reason: large signed batch files
Message broker
-> filesystem journal
reason: durable middleware storage
This is polyglot persistence. It is useful only when each choice has a reason. Adding technologies without clear ownership creates complexity.
Practical Workflow
- List the main data types in the system.
- For each data type, identify the access pattern.
- Mark which data needs ACID transactions.
- Mark which data can be stale or rebuilt.
- Mark which data is structured, flexible, graph-like, or file-oriented.
- Assign one storage owner for each data type.
- Avoid direct database sharing across services unless there is an explicit reason.
- Define integration between stores through APIs, events, or controlled synchronization.
- Document consistency expectations for each store.
- Add monitoring and recovery procedures for every storage tier.
Storage Decision Table
| Need | Storage direction |
|---|---|
| Stable structure and ACID | Relational database |
| Fast lookup by known key | Key value store |
| Temporary session state | Key value store |
| Flexible JSON-like records | Document database |
| Relationship traversal | Graph database |
| Large batch file exchange | Filesystem or object storage |
| Middleware journaling | Filesystem-backed storage |
| High-volume cache reads | Cache in front of persistent store |
The table is a starting point, not a replacement for design. Real systems need constraints, operations, and team skills considered too.
Common Mistakes
The first mistake is using one database for everything. That can make simple operations harder and specialized operations slower.
The second mistake is using too many storage technologies without ownership. Every storage engine adds deployment, monitoring, backup, recovery, and knowledge requirements.
The third mistake is sharing one database directly between many services. This tightly couples service release cycles, making ownership unclear.
The fourth mistake is storing critical business data only in a cache or temporary store.
The fifth mistake is using files as a searchable database. Files are useful for exchange and large payloads, but indexing and query needs require another layer.
Checklist
- Every storage technology has a documented purpose.
- Each data type has a clear owner.
- ACID data is stored where transactionality is supported.
- Temporary data has an expiration or eviction rule.
- Cached data has stale data rules.
- Flexible documents do not hide critical relational constraints.
- Filesystem usage is limited to suitable exchange or infrastructure needs.
- Cross-store synchronization has a defined mechanism.
- Backup and recovery are planned per storage tier.
- The team can operate every selected technology.
Conclusion
A multi-tier storage strategy lets Java teams match persistence technology to the real needs of each use case.
Use relational databases for structured transactional data. Use key-value stores for fast lookup, sessions, and caching. Use NoSQL where the data shape or query model fits. Use file systems and object storage for large-scale data exchange and infrastructure needs.
The goal is not to use every storage option. The goal is to avoid forcing every data problem into the same tool.