0%

MongoDB事务

事务是是指一系列操作,全部执行成功则提交,有一个执行失败则全部回滚,这也是事务四大特性(ACID)之一的原子性。至于其他特性,不同的DB都有不同的实现方式。

一、基础

  1. 事务是指由一系列数据库操作组成的一个完整的逻辑过程,这个过程中的所有操作要么都成功,要么都不成功。比如:常见的例子就是银行转账的例子,一次转账操作会包含多个数据库操作,而这些数据库操作需要放到一个事务当中,保证其要么都成功,要么都不成功。

    • 事务的四个特性ACID
      • 原子性(Atomicity)
      • 一致性(Consistency)
      • 隔离性(Isolation)
      • 持久性(Durability)
  2. MongoDB单文档原生支持原子性,也具备事务的ACID特性。MongoDB在4.0版本支持了多文档事务,包括对复制集的多表、多行的事务支持,4.2版本对分片集多表、多行事务操作进行了支持。MongoDB在事务操作中会分别使用到readConcern、writeConcern、readPreference这几个选项,用于控制Session的行为。

    • Write Concern:决定一个写操作落到多少个节点上才算成功,这决定了MongoDB是否成功写入数据,writeConcern配置项:

      • w:0:发起写入操作,不关心是否成功(适用于性能要求高,但不关注正确性的场景)

      • w:1~任意节点数:写操作需要被复制到指定节点数才算成功

      • w:majority:写操作需要被复制到大多数节点上才算成功(适用于对数据安全性要求比较高的场景,该选项会降低写入性能)

      • w:all:复制到全部节点上才算成功

        • w设置的节点数越多等待的延迟也就越大
      • 其他选项

        • j:true:默认情况j:false,写操作到达内存算作完成;如果设置为j:true,写操作只有到达journal文件才算成功。
        • wtimeout:写入超时时间,仅w的值大于1时有效。
          • 当指定w:n时数据需要成功写入n个节点才算成功,如果写入过程中有节点故障,可能导致这个条件一直不能满足从而一直不能向客户端发送确认结果,针对这种情况客户端可设置wtimeout选项来指定超时时间,当写入过程持续超过该时间仍未结束则认为写入失败
      • 示例

        1
        2
        3
        4
        5
        writeConcern: {
        w:"majority" // 大多数原则
        j:true,
        wtimeout: 5000,
        }
    • Read Preference:决定使用哪一个节点来满足正在发起的读请求,可选值包括:

      • primary:默认,只选择主节点,保证每次读到的数据都是最新的
      • primaryPerferred:优先选择主节点,如果不可用则选择从节点
      • secondary:只选择从节点
      • secondaryPerferred:优先选择从节点,如果从节点不可用则选择主节点
      • nearest:选择最近的节点,针对多区域部署的情况
        • Tag:readPreference只能控制使用一类节点,Tag则可以将节点选择控制到一个或几个具体的节点
    • Read Concern:在readPerference选择了指定节点后,readConcern决定这个节点上的数据哪些是可读的,类似于关系型数据库的隔离级别:

      • local:默认,读取所有可用且属于当前分片的数据
      • available:读取所有可用的数据
      • majority:读取在大多数节点上提交完成的数据
      • linearizable:可线性化读取文档
      • snapshot:读取最近快照中的数据
  3. Session是3.6版本引入的概念,引入其主要目的就是为实现多文档事务做准备,它本质上就是一个「上下文」。在<3.6的版本MongoDB只管理单个操作的上下文,mongod服务进程接收到一个请求即为该请求创建一个上下文(源码里对应OperationContext),然后在服务整个请求的过程中一直使用这个上下文,内容包括请求耗时统计、请求占用的锁资源、请求使用的存储快照等信息,有了Session之后就可以让多个请求共享一个上下文,让多个请求产生关联,从而有能力支持多文档事务。

    • 每个Session包含一个唯一的标识lsid,在4.0版本里用户的每个请求可以指定额外的扩展字段,主要包括:
      • lsid:请求所在Session的ID, 也称logic session id
      • txnNmuber:请求对应的事务号,事务号在一个Session内必须单调递增
      • stmtIds:对应请求里每个操作(以insert为例,一个insert命令可以插入多个文档)操作ID
  4. journal

  5. 命令行操作

    • 获取会话:session = db.getMongo().startSession()
    • 开启事务:session.startTransaction()
    • 获得集合:user = session.getDatabase("study").user
    • 操作文档:user.insert({name:"测试"})
    • 提交事务:session.commitTransaction
    • 回滚事务:session.abortTransaction()

二、使用

三、参考

  1. 参考一
  2. 参考二
  3. 参考三
  4. 参考四
  5. 参考五