- 文档结构设计:
- 明确每个集合(表)的文档结构,使用
BSON Schema
进行定义。例如,订单文档可能包含订单编号、用户ID、商品列表、总价等字段,商品文档包含商品ID、名称、价格等,用户文档包含用户ID、姓名、联系方式等。确保每个字段的数据类型、必填性等都有清晰定义。
- 采用嵌套文档和引用相结合的方式。对于订单中的商品列表,可以使用嵌套文档形式包含商品简要信息(如商品ID、名称、价格),同时保留对商品集合的引用,以便获取完整商品信息。这样既减少数据冗余,又能方便查询。
- 插入前校验:
- 字段存在性校验:在应用层代码中,根据定义的文档结构,检查要插入的文档是否包含所有必填字段。例如,订单文档必须包含订单编号、用户ID、商品列表等必填字段。
- 数据类型校验:同样在应用层,验证每个字段的数据类型是否正确。如订单总价应为数值类型,用户ID应为特定格式的字符串或ObjectId。
- 引用完整性校验:如果文档包含对其他集合的引用,如订单中的用户ID引用用户集合,在插入订单前,检查对应的用户文档是否存在。可以使用
findOne
方法查询被引用集合,确认引用的文档是否存在。
- 业务规则校验:
- 订单总价校验:在订单插入前,根据商品列表中的商品价格和数量计算总价,并与订单文档中的总价进行对比,确保两者一致。
- 库存校验:对于商品,在插入订单时,检查商品的库存是否足够。从商品集合中获取商品库存信息,对比订单中商品数量,若库存不足则拒绝插入订单。
- 事务处理(MongoDB 4.0+):
- 使用多文档事务来确保跨集合操作的一致性。例如,当插入订单时,同时更新商品库存(减少库存数量)和用户相关信息(如积分增加等)。
- 开启事务后,执行一系列操作(插入订单、更新商品、更新用户),如果其中任何一步失败,事务回滚,保证数据的一致性。示例代码如下(以Node.js为例):
const { MongoClient } = require('mongodb');
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
async function insertOrder(order) {
try {
await client.connect();
const session = client.startSession();
session.startTransaction();
const orderCollection = client.db('ecommerce').collection('orders');
const productCollection = client.db('ecommerce').collection('products');
const userCollection = client.db('ecommerce').collection('users');
// 插入订单
await orderCollection.insertOne(order, { session });
// 更新商品库存
for (const item of order.productList) {
await productCollection.updateOne(
{ _id: item.productId },
{ $inc: { stock: -item.quantity } },
{ session }
);
}
// 更新用户积分等信息
await userCollection.updateOne(
{ _id: order.userId },
{ $inc: { points: order.totalPrice * 0.1 } },
{ session }
);
await session.commitTransaction();
} catch (e) {
console.error(e);
} finally {
await client.close();
}
}
- 数据库层面约束:
- 唯一索引:在关键字段上创建唯一索引,如订单编号、商品ID、用户ID等,防止重复数据插入。例如,为订单集合的订单编号字段创建唯一索引:
db.orders.createIndex({ orderNumber: 1 }, { unique: true });
- **复合索引**:根据常用查询条件创建复合索引,提高查询性能,同时在一定程度上保证数据完整性。例如,若经常根据用户ID和订单状态查询订单,可以创建复合索引:
db.orders.createIndex({ userId: 1, orderStatus: 1 });
- 日志记录与监控:
- 记录所有插入操作的日志,包括成功和失败的记录。日志应包含插入的文档内容、操作时间、操作结果等信息,以便后续排查问题。
- 定期监控插入操作的成功率、失败原因分布等指标,及时发现潜在的数据一致性问题,并针对性地优化校验机制和策略。