MongoDB - 事务

写操作事务

writeConcern - w

writeConcern决定写操作落到多少节点上才算成功,其取值包括:

  • 0:发起写操作,不关心结果
  • n 1 <= n <= 集群最大数据节点数:写操作复制到n个节点才算成功。
  • majority: 写操作被复制到大多数节点才算成功
    发起写操作的线程将阻塞到写操作到达指定节点数才算成功;三节点复制集,默认是1,即主节点写好了就成了; 对于重要数据设置w:majority,对于普通数据设置w:1

语法:
db.test.insert({count:1}, {writeConcern:{w:3,wtimeout:3000}})

journal - j

journal决定写操作到什么程度才算成功

  • true: 写操作落到journal文件中
  • false: 写到内存就算成功

读操作事务

读数据,主要有两个问题:

  • 从哪里读?- readPreference
  • 什么样的数据可以读?(隔离性) - readConcern

readPreference

  • primary: 只从主节点读
  • primaryPreferred:优先主节点
    🌰 用户下单后转到订单详情页,可能从节点还没有复制到新订单
  • secondary: 只从从节点
    🌰 生成报表
  • secondaryPreferred: 从节点优先
    🌰 用户查询自己的历史订单
  • nearest: 选择最近的节点
    🌰 用户上传的图片分发到全世界

语法:
db.test.find({a:123}).readPref("secondary")

Tag

例如五节点复制集,三个硬件好一点的,打上tag"online",另外两个打上tag"analyse",生成报表只选择"analyse"节点,如图所示:
tag示例

readConcern

这个节点上哪些数据是可以读的:

  • available: 所有可用数据
  • local:所有可用且属于当前分片
    local是默认值,在复制集上local和available无区别;只是在分片集上,当做chunk迁移时,只读当前分片,否则把还没迁移成功的另外个分片上迁移中的数据也读出来
  • majority:大多数节点提交完成的数据
    实现方式:和MySQL的MVCC类似,节点上保存多个版本的数据,根据需求返回不同版本数据。使用majority可以有效避免“脏读”。

首先,MongoDB对事务的支持更多指的是一个写操作能否被持久化下来,所以“提交”的概念就是,写到了多数节点(那么数据就不会丢失,永远持久化了),在这个层面上,读majority就不会“脏读”,读到的数据都是落到大多数节点的,而不会因为节点crash某个写操作在读之后丢失了(相当于回滚了)

  • linearizable:可线性化读取文档,保证该“读”能读到上一个“写”,保证操作的线性顺序
  • snapshot:读取最近快照中的数据 (隔离级别最高,相当于serializable)

安全的读写分离

readConcern和writeConcern配合实现安全的读写分离
🌰用户下单,并从从节点读订单数据:
不安全:

db.orders.insert({oid:100, sku:"kite", q:1})
db.orders.find({oid:100}).readPref("secondary")

安全:

db.orders.insert({oid:100, sku:"kite", q:1},{writeConcern:{w:"majority"}})
db.orders.find({oid:100}).readPref("secondary").readConcern("majority")

多文档事务

mongoDB 4.2之后全面支持了多文档事务,但是推荐还是能不用尽量不用,尽量通过合理的数据模型设计来规避事务的必要性。

语法:

try (ClientSession clientSession = client.startSession()) {
  clientSession.startTransaction();
  collection.insertOne(clientSession, docOne);
  collection.insertOne(clientSession, docTwo);
  clientSession.commitTransaction();
}

注意:

  • 多文档事务的读必须从主节点读
  • 使用MongoDB4.2兼容的驱动
  • readConcern只应该在事务级别设置,不能在每次读写操作上
posted @   rachel_aoao  阅读(726)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
点击右上角即可分享
微信分享提示