很多人在用NoSQL的时候,都会遇到一个实际问题:我这条数据写了一半,系统崩了,另一半没写进去,那不是乱套了?比如你在做个抢购功能,库存减了,订单却没生成,用户钱扣了但没买到东西,这可不行。这时候就轮到“事务”出场了。
传统印象里的NoSQL:快、灵活,但不讲规矩
早年的MongoDB、Cassandra这些NoSQL数据库,主打的就是高并发、水平扩展和灵活的Schema。为了追求性能,它们大多牺牲了事务支持。那时候你执行一组操作,只能靠应用层自己兜底,比如记录日志、做补偿机制,听起来就很累。
但现在不一样了
以MongoDB为例,从4.0版本开始就支持多文档事务了。只要你用的是副本集或分片集群(生产环境基本都是),就可以在一次会话里包办多个写操作,要么全成功,要么全回滚。
session.startTransaction();
try {
db.orders.insertOne(order, { session });
db.inventory.updateOne(
{ item: "A" },
{ $inc: { qty: -1 } },
{ session }
);
session.commitTransaction();
} catch (error) {
session.abortTransaction();
throw error;
}
这段代码就是典型的事务写法。订单加进去的同时扣库存,中间出问题就整个撤销。对业务逻辑来说,安心多了。
其他NoSQL也在跟进
DynamoDB虽然原生不支持跨表事务,但提供了TransactWriteItems和TransactGetItems,能保证多个操作的原子性。Cassandra也在特定条件下支持轻量级事务(Lightweight Transactions),用Paxos协议实现CAS(比较并交换)操作。
当然,这些事务能力通常有代价。比如性能比单条操作低,跨分片事务更复杂,超时限制也更严格。所以不是所有场景都适合开事务,得看你的数据一致性要求有多高。
如果你做的只是记录用户点击日志、设备上报这类“丢了也不致命”的数据,那完全没必要上事务。但涉及资金、订单、账户状态这些敏感信息,就得认真考虑要不要开启事务支持了。
现在的NoSQL已经不像过去那样“野路子”了。它们在保持高性能的同时,逐步补齐了事务这块短板。选型时别再默认“NoSQL不支持事务”,先查查你用的版本和部署模式支不支持,说不定早就ready了。