无共享数据库的产品与订单微服务设计及数据关联方案咨询
Great question—this is a common challenge when working with microservices that own their own data. Let's break this down step by step:
Since cross-database joins aren't possible, you have two primary approaches to combine order and product data:
Client-Side Composition
- The client first calls the Order Microservice to fetch the order details, which includes the list of product IDs (or line items with product IDs).
- Then, the client makes a second call to the Product Microservice, passing those product IDs to retrieve their full details.
- Pros: Simple to implement, no extra infrastructure required.
- Cons: Requires multiple round trips between client and services, and the client has to handle data aggregation logic.
Orchestration Layer (API Gateway/Composite Service)
- Create an intermediary service (like an API gateway or dedicated composite service) that handles the data aggregation on behalf of the client.
- The client makes a single request to this layer, which internally calls the Order Microservice, uses the returned product IDs to call the Product Microservice, combines the data, and sends the final result back to the client.
- Pros: Client gets a single, unified response; reduces round trips.
- Cons: Adds an extra component to maintain, and you need to handle partial failures (e.g., if Product service is down but Order service is working).
Pro tip: Cache frequently accessed product details in the orchestration layer or Order Microservice to reduce latency and load on the Product service.
Yes, you should store references to products in the Order model—but avoid storing a raw list of product IDs in the main orders table. Instead, use a normalized structure within the Order service's database to track line items:
Core Order Table
Stores metadata about the order itself (customer info, status, date, total amount).
Order Items Table
Stores individual line items for each order, including product IDs, quantities, and the unit price at the time of purchase. Storing the unit price is critical—it decouples historical order data from changes to product prices in the Product service, ensuring your order records remain accurate even if product details change later.
Here's a sample SQL schema for the Order service's database:
-- Main orders table CREATE TABLE `orders` ( `order_id` VARCHAR(36) PRIMARY KEY, -- UUID works well for distributed systems `customer_id` VARCHAR(36) NOT NULL, `order_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `status` VARCHAR(20) NOT NULL CHECK (`status` IN ('PENDING', 'PROCESSING', 'SHIPPED', 'DELIVERED', 'CANCELLED')), `total_amount` DECIMAL(10,2) NOT NULL ); -- Order items table to track individual products in the order CREATE TABLE `order_items` ( `order_item_id` VARCHAR(36) PRIMARY KEY, `order_id` VARCHAR(36) NOT NULL, `product_id` VARCHAR(36) NOT NULL, `quantity` INT NOT NULL CHECK (`quantity` > 0), `unit_price` DECIMAL(10,2) NOT NULL, FOREIGN KEY (`order_id`) REFERENCES `orders`(`order_id`) ON DELETE CASCADE );
Independent Databases (More Common & Recommended)
This is the standard approach for mature microservice architectures because:
- It enforces loose coupling: each service owns and controls its data, so schema changes in one service don't break others.
- Enables independent scaling: you can scale the Order service's database separately from the Product service's if one has higher traffic.
- Improves fault isolation: if one database goes down, the other service can still operate (e.g., Order service can accept new orders even if Product service is unavailable).
Shared Databases (Less Common)
Shared databases are typically used only in early-stage or small systems where complexity is low. The downsides are:
- Tight coupling: schema changes require coordination across all services using the database.
- No independent scaling: you can't optimize database resources for individual services.
- Higher risk: a bug in one service can corrupt data used by others.
内容的提问来源于stack exchange,提问作者Sudipto Roy

