认识 MongoDB 的事务

发表于 2023-03-03

MongoDB 的事务

因为 MongoDB 天然支持集群,所以事务的配置参数主要涉及集群,即 CAP 理论的取舍。

写事务

写事务参数(writeConcern)

  • 参数
    • w
      • 数据被写入 Mongo 服务/实例数量
    • j
      • 数据被写入 Mongo 服务/实例的磁盘日志
  • w 取值
    • 0
      • 发起写操作,不关心是否成功
    • 1(集群节点数)
      • 写操作被复制到指定节点数才算成功
    • majority
      • 写操作被复制到大多数节点上才算成功
    • 例子:
      • {"writeConcern": { "w": 0}}
      • {"writeConcern": { "w": "majority"}}
  • j 取值
    • true
      • 数据被写入 Mongo 服务/实例的磁盘日志
    • false
      • 数据被写入 Mongo 服务/实例的内存
    • 例子:
      • {"writeConcern": { "j": true}}

流程图

事务流程图

命令说明

可通过命令的控制,实现 MongoDB 集群节点之间的数据一致性,以此来快速验证事务。

  • 锁定节点同步数据
    • db.fsyncLock()
  • 解锁节点同步数据
    • db.fsyncUnlock()
  • 给服务节点打标签
    • conf = rs.conf()
      • 获取当前的复制集群配置
    • conf.members[0].tags = { "<tag>": "<string>", ...}
      • 修改标签配置
      • conf.members[0].tags = { "tag1": "string1", "tag2": "string2"}
    • rs.reconfig(conf)
      • 将修改后的配置设置回集群
    • rs.conf()
      • 查看集群配置

读事务

因为 MongoDB 的集群特点,所以其读取数据也有一些集群特性的配置。

主要分为两部分:

  • readPreference
    • 指定从哪个节点读取。
    • 例如:优先从复制节点读取。
  • readConcern
    • 读取事务(writeConcern)写入状态。
    • 例如:读取当前节点上的所有数据,不论是否因为集群其他节点失败而回滚。

readPreference

  • mode
    • primary
      • 只从主节点读取
    • primaryPreferred
      • 主要从主节点读取,失败才从复制节点读取
    • secondary
      • 只从复制节点读取
    • secondaryPreferred
      • 主要从复制节点读取,失败才从主节点读取
    • nearest
      • 从最近节点
  • tagSet
    • 标记集
    • 在集群中给各个服务节点打上标签
    • 通过标记集可以从指定的节点上读取数据
    • 例如:
      • 将使用 region 将集群划分为:West、East
      • db.order.find({}).readPref("secondaryPreferred", [{"region": "West"}])
        • 从 region 标签为 West 的服务节点上读取
  • 使用
    • cursor.readPref(mode, tagSet)
  • 例子
    • db.order.find({}).readPref("secondary", [{"tag", "read"}])

readConcern

  • 取值
    • available
      • 读所有可用的数据
    • local
      • 读所有可用且属于当前分片的数据(主节点默认值
        • 例如在分片数据迁移操作的时候
        • 可能出现数据迁移过来了部分,但是迁移过程还没完成
        • 这个时候部分数据在两个服务节点都有
        • 只是旧数据任然有效,新数据还未生效
        • 只有当确认完成,旧数据失效,新数据生效才迁移完成
    • majority
      • 读取大多数节点上提交完成的数据(常用
      • 类似读已提交(大多数节点提交)
      • 需要开启 majority 配置
        replication:
            enableMajorityReadConcern: true
    • linearizable
      • 线性化读取数据
      • 类似读已提交(所有节点提交)
      • 会和其他节点校验当前数据是否是最新
    • snapshot
      • 读取最近的快照数据(MVCC 的)
      • 可重复读
  • 使用
    • cursor.cursor.readConcern(<level>)
  • 例子
    • db.order.find({}).readConcern("majority")

多文档事务

事务命令

  • session = db.getSession()
    • 获取 Session
  • session.startTransaction()
    • 开启事务
  • demo = session.getDatabase("demo")
    • 通过开启事务的 Session 获取 DataBase
  • session.commitTransaction()
    • 提交事务
  • session.abortTransaction()
    • 放弃事务

注意

多文档和 writeConcern

  • 多文档和 writeConcern 不能同时使用

Mongo 多文档事务与 Java

手动控制事务

// 获取 Session
ClientSession clientSession = mongoClient.startSession();
// 开启事务
clientSession.startTransaction();
// 命令
// 提交事务
clientSession.commitTransaction();
// 放弃事务
clientSession.abortTransaction();

SpringBoot 注解管理事务

@Bean
public MongoTransactionManager transactionManager(MongoDatabaseFactory factory) {
    return new MongoTransactionManager(factory);
}