前面提到过,MongoDB从4.0开始支持复制集下的多文档事务,从4.2开始支持分片集群下的多文档事务。至此,MongoDB才算是完全支持多文档事务。但这并不代表大家可以毫无节制地使用它,相反,对事务的使用原则应该是:能不用就不用。因为事务的底层实现就是使用锁,而分布式环境下的事务,还有复杂的节点协调机制,额外开销巨大,对性能存在严重的影响。因此,我们应当尽量通过合理的文档设计,来规避使用事务的必要性。
MongoDB的多文档事务可以跨文档、集合以及数据库。当事务提交时,将执行并保存在事务中所做的所有数据更新。如果事务中有任何操作失败,事务中止,事务中所有数据更新操作都将被丢弃。在事务提交之前,事务中的写入或更新操作在事务外部不可见。
MongoDB的事务错误处理机制也不同于关系数据库:
MongoDB默认事务隔离级别是读已提交,即事务完成前,事务外的操作对该事务所做的修改不可访问。而事务内部则是可重复读级别,即事务内可以读到该事务内之前的所有修改,这点其实跟关系数据库是一致的。
MongoDB多文档事务的使用方式也与关系数据库非常相似,都是类似的3段式流程:
try (ClientSession clientSession = client.startSession()) {
// 开启事务
clientSession.startTransaction();
// 操作数据
collection.insertOne(clientSession, docOne);
collection.insertOne(clientSession, docTwo);
// 提交事务
clientSession.commitTransaction();
}
最后是使用多文档事务的几点注意事项:
// 连接到复制集
mongodb://节点1,节点2,节点3.../database?[options]
// 连接到分片集
mongodb://mongos1,mongos2,mongos3.../database?[options]
常见的连接字符串参数有:
基于前面提到的原因,驱动已经知晓在不同的mongos之间实现负载均衡,而复制集则需要根据节点的角色来选择发送请求的目标。如果在mongos或复制集上层部署负载均衡:
因此,不要在mongos或复制集上层放置负载均衡器,让驱动处理负载均衡和自动故障恢复。
除了前面的连接字符串和负载相关的内容,有没有发现,这些最佳实践其实也适用于MySQL等关系数据库,甚至它们在原理上都是类似的,比如分页问题,在MySQL(innodb)中计算count也是一样的耗时;数据量大时,skip一个很大的页码页非常慢。再比如事务问题,都是尽量不使用事务,如必须使用也需要尽量缩小事务的范围。
本文内容参考:极客时间 - MongoDB高手课,对原课程中的相关内容作了增补
人生在世,错别字在所难免,无需纠正。
@{{child.atAuthor}}