Part 3: Storing the Treasures — Azure Data & Storage Services
CloudVault's data is growing fast. Marcus explores Azure's data services—SQL Database for relational data, Cosmos DB for globally distributed workloads, and Blob Storage for files. We design a multi-tier data architecture and implement production-ready Java code for each service.
Part 3: Storing the Treasures — Azure Data & Storage Services
Designing CloudVault’s Data Architecture
The Data Problem
Week three. CloudVault’s API is running smoothly, but now the team faces a new challenge: where should they store data?
Marcus sits in a meeting with the data team. They have three main data requirements:
- Account information — Structured, relational data with ACID guarantees
- Transaction history — High-volume, time-series data that needs global distribution
- Document uploads — Large files (PDFs, images) that need quick retrieval
“We could use a single database for everything,” suggests one engineer.
“But that won’t scale,” counters another. “We need different solutions for different problems.”
Marcus nods. This is the core insight: one database doesn’t fit all use cases. You need to choose the right tool for each problem.
The Data Service Spectrum
Azure offers different data services optimized for different patterns:
| Service | Best For | Consistency | Scaling |
|---|---|---|---|
| SQL Database | Relational, ACID, complex queries | Strong | Vertical |
| Cosmos DB | Global distribution, high throughput | Eventual | Horizontal |
| Blob Storage | Large files, unstructured data | Strong | Unlimited |
Option 1: Azure SQL Database
Azure SQL Database is a managed relational database service. You define schemas, relationships, and constraints. It guarantees ACID properties.
When to Use SQL Database
- You have structured, relational data
- You need ACID guarantees (financial transactions)
- You need complex queries with JOINs
- Your data fits in a single region
Setting Up SQL Database
az sql server create \ --resource-group rg-cloudvault-prod \ --name sqlserver-cloudvault \ --admin-user sqladmin \ --admin-password "ComplexPassword123!"
az sql db create \ --resource-group rg-cloudvault-prod \ --server sqlserver-cloudvault \ --name cloudvault_db \ --service-objective S0Connecting from Java
Add dependencies to pom.xml:
<dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>12.2.0.jre11</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>Configure in application.yml:
spring: datasource: url: jdbc:sqlserver://sqlserver-cloudvault.database.windows.net:1433;database=cloudvault_db;encrypt=true;trustServerCertificate=false username: sqladmin password: ${DB_PASSWORD} driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver jpa: hibernate: ddl-auto: validateDefine your entity:
@Entity@Table(name = "accounts")@Data@NoArgsConstructor@AllArgsConstructorpublic class Account {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Column(nullable = false, unique = true) private String accountNumber;
@Column(nullable = false) private String ownerName;
@Column(nullable = false) private BigDecimal balance;
@CreationTimestamp @Column(nullable = false, updatable = false) private LocalDateTime createdAt;
@UpdateTimestamp @Column(nullable = false) private LocalDateTime updatedAt;}Cost: ~$15-50/month
Option 2: Azure Cosmos DB
Azure Cosmos DB is a globally distributed, multi-model database. It guarantees low latency (< 10ms) anywhere in the world and scales horizontally.
When to Use Cosmos DB
- You need global distribution with low-latency reads/writes
- You have high throughput requirements
- You want flexible schema (documents can differ)
- You need multiple regions with automatic failover
Setting Up Cosmos DB
az cosmosdb create \ --resource-group rg-cloudvault-prod \ --name cosmosdb-cloudvault \ --kind GlobalDocumentDB \ --default-consistency-level Eventual
az cosmosdb sql database create \ --resource-group rg-cloudvault-prod \ --account-name cosmosdb-cloudvault \ --name transactions_db
az cosmosdb sql container create \ --resource-group rg-cloudvault-prod \ --account-name cosmosdb-cloudvault \ --database-name transactions_db \ --name transactions \ --partition-key-path "/accountId" \ --throughput 400Connecting from Java
Add dependencies:
<dependency> <groupId>com.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>4.50.0</version></dependency>Define your document model:
@Data@NoArgsConstructor@AllArgsConstructorpublic class Transaction {
@JsonProperty("id") private String id;
@JsonProperty("accountId") private String accountId;
@JsonProperty("type") private String type; // DEBIT, CREDIT
@JsonProperty("amount") private BigDecimal amount;
@JsonProperty("timestamp") private LocalDateTime timestamp;
@JsonProperty("status") private String status;}Create a repository:
@Repositorypublic class TransactionRepository {
@Autowired private CosmosContainer cosmosContainer;
public void save(Transaction transaction) { transaction.setId(UUID.randomUUID().toString()); transaction.setTimestamp(LocalDateTime.now()); cosmosContainer.createItem(transaction); }
public List<Transaction> findByAccountId(String accountId) { String query = "SELECT * FROM transactions t WHERE t.accountId = @accountId"; return cosmosContainer.queryItems(query, Transaction.class) .stream().collect(Collectors.toList()); }}Cost: ~$25-100/month depending on throughput
Option 3: Azure Blob Storage
Azure Blob Storage is for storing large, unstructured data: files, images, videos, backups.
Setting Up Blob Storage
az storage account create \ --resource-group rg-cloudvault-prod \ --name cvaultstorage \ --kind StorageV2 \ --sku Standard_LRS
az storage container create \ --account-name cvaultstorage \ --name documentsUploading Files from Java
Add dependencies:
<dependency> <groupId>com.azure</groupId> <artifactId>azure-storage-blob</artifactId> <version>12.23.0</version></dependency>Upload files:
@Servicepublic class DocumentService {
@Autowired private BlobServiceClient blobServiceClient;
private static final String CONTAINER_NAME = "documents";
public String uploadDocument(String accountId, MultipartFile file) throws IOException { BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(CONTAINER_NAME);
String blobName = accountId + "/" + UUID.randomUUID() + "/" + file.getOriginalFilename();
BlobClient blobClient = containerClient.getBlobClient(blobName); blobClient.upload(file.getInputStream(), file.getSize(), true);
return blobClient.getBlobUrl(); }}Cost: ~$0.018 per GB/month (very cheap)
Marcus’s Data Architecture
After analyzing CloudVault’s needs, Marcus designs:
- SQL Database for account data (relational, ACID)
- Cosmos DB for transaction history (high volume, global)
- Blob Storage for document uploads (files, images)
“This gives us the best of all worlds,” Marcus explains. “We get ACID guarantees where we need them, global scale for transactions, and unlimited storage for files.”
Consistency Models
A critical concept: consistency. When you write data, how quickly can other processes see it?
- Strong Consistency: Reads always see the latest write (SQL Database)
- Eventual Consistency: Reads might see stale data temporarily (Cosmos DB)
For financial transactions, use SQL Database. For analytics, Cosmos DB is fine.
Key Takeaways
- SQL Database for relational, ACID-guaranteed data
- Cosmos DB for global distribution and high throughput
- Blob Storage for files and unstructured data
- Choose based on your data patterns, not just the latest technology
- Understand consistency guarantees — they affect your architecture
What’s Next?
Marcus has designed the data architecture. Now he needs to connect everything securely. In the next chapter, we’ll explore Azure’s networking services and design a secure, multi-tier architecture.
The treasures are stored. Now let’s protect them.
This is Part 3 of a 6-part series: “The Azure Ascent: A Backend Engineer’s Journey to Cloud Mastery.”