美文网首页
mongoose使用事务Transaction

mongoose使用事务Transaction

作者: maomizone | 来源:发表于2022-04-08 13:32 被阅读0次

具体的教程请看官方文档:https://mongoosejs.com/docs/transactions.html

  • 我这里简单总结下我项目是咋用的,我这里有个编辑设备的接口,要更新两个doc,设备doc,以及另外一个一对一的doc

  • 忽略我代码中的数学运算,首先我的equip文档是没有使用到事务的,这为我后面埋了一个坑,我首先判断这个设备文档,以及和设备文档形成一对一的allZone文档的关联id是否存在于我的设备doc中,如果有问题就报错了,没有问题就开始事务了

  • 然后咔咔咔一顿计算,我要开始save数据了,我就记着官方有句话是save是默认带着session去save的,然后我就偷懒没加save({session}),代码最后我故意抛出异常,结果我的equip doc还是保存成功了,把我郁闷的,后面才留意一段话,就是首先你的文档是通过session find的,那你才能在save的时候直接引用到session,所以在equip.save时我们要手动加上{session},所以最终的结果是别偷懒了,都加上就不会错

写法1
  /**
   * POST
   * 编辑设备
   * api/equip/editEquip
   * id 设备id
   */
  export async function editEquip(req: any, res: any) {
    if (!req.body.id) {
      return mongooseTool.sendRes(false, '请传入设备id', res)
    }

    const equip = await EquipmentModel.findById(req.body.id)

    // 如果未查询到设备,或者设备表中找不到关联填写区的ID(可能是人为误删之类)
    // 都要报错
    if(!equip){
      return mongooseTool.sendRes(false, '找不到该设备', res)
    }else if(!equip.allZoneID){
      return mongooseTool.sendRes(false, '数据出错', res)
    }

    const session = await mongoose.connection.startSession()

    // 开始事务处理
    await session.withTransaction(async () => {
      equip.unitCostTarget = req.body.unitCostTarget ?? 0

      const allZone = await AllZoneModel.findById(equip.allZoneID).session(session)
      allZone.AutoWHInnerleft = req.body.AutoWHInnerleft ?? 0
      allZone.BSInner = req.body.BSInner ?? 0
      allZone.ManualStations = req.body.ManualStations ?? 0

      // 设备总数=填写区域数量累加
      equip.num = allZone.AutoWHInnerleft + allZone.BSInner + allZone.ManualStations

      // Unit Cost Target>0时,GPA差距=(Unit Cost Target-单位成本)/单位成本;
      // Unit Cost Target=0时,CPA差距为空
      // 合计成本目标:假如Unit Cost Target > 0,等于Unit Cost Target*物料总数,假如Unit Cost Target <=0,等于单位成本 *总数。
      if(equip.unitCostTarget > 0 ){
        equip.gap = equip.unitCost > 0 ? compute.Div(compute.Sub(equip.unitCostTarget, equip.unitCost), equip.unitCost, 2) : 0
        equip.costTarget = compute.Mul(equip.unitCostTarget, equip.num)
      }else {
        equip.gap = 0
        equip.costTarget = compute.Mul(equip.unitCost, equip.num)
      }

      equip.cost = equip.costTarget

      // If you get a Mongoose document from findOne() or find() using a session,
      // the document will keep a reference to the session and use that session for save().
      // 由于equip不是通过session查询到的,所以如果不加{session},那么equip.save不会被认为是事务的一部分,我们需要手动加上
      await equip.save({ session })

      // allZone是通过session查询到的,所以可以不加{session},文档会自动使用该session来执行save操作,被认为是事务的一部分
      await allZone.save()

      // 故意报个错,会进入到catch,不会执行成功的语句,最终执行endSession
      // throw new Error('Oops')

      mongooseTool.sendRes(true, equip, res)
    }).catch(err => {
      console.log(`editEquip接口报错了 ${err.message}`)
      mongooseTool.sendRes(false, '编辑设备失败', res)
    })
    session.endSession();
  }
}
写法2
/**
   * POST
   * 获取填写区域
   * api/equip/getInputs
   * id 设备id
   */
  export async function getInputs(req: any, res: any) {
    if (!req.body.id) {
      return mongooseTool.sendRes(false, '请传入必要参数', res)
    }

    const session = await mongoose.connection.startSession()
    session.startTransaction()

    try {
      const equip = await EquipmentModel.findById(req.body.id).session(session)
      // 如果未查询到设备则报错
      if (!equip) {
        return mongooseTool.sendRes(false, '找不到该设备', res)
      }

      // 如果没有需要新增一个
      if (!equip.allZoneID) {
        const allZone = new AllZoneModel({
          _id: new mongoose.Types.ObjectId(),
          AutoWHInnerleft: 0,
          BSInner: 0,
          ManualStations: 0
        })

        await allZone.save({ session })

        equip.allZoneID = allZone._id

        await equip.save({ session })

        // 故意报个错
        // throw new Error('Oops')

        await session.commitTransaction()

        mongooseTool.sendRes(true, allZone, res)
      } else {
        // 如果找到了直接返回
        const allZone = await AllZoneModel.findById(equip.allZoneID).exec()
        mongooseTool.sendRes(true, allZone, res)
      }
    } catch (err) {
      mongooseTool.sendRes(false, '获取设备失败', res)
    } finally {
      session.endSession()
    }
  }

相关文章

  • mongoose使用事务Transaction

    具体的教程请看官方文档:https://mongoosejs.com/docs/transactions.html...

  • Yii2 事务

    事务(Transaction) 在Yii中,使用 yii\db\Transaction 来表示数据库事务。 一般情...

  • WCDB 入门

    iOS+macOS使用教程 ORM使用教程 demo 事务一 事务二 事务(Transaction),一般是指要做...

  • @Transaction使用&@事务失效

    Transaction是Spring提供的关于事务的支持,Spring事务管理分为编码式和声明式两种方式。声明式事...

  • 谈谈Transaction——MySQL事务处理分析

    MySQL 事务基础概念/Definition of Transaction 事务(Transaction)是访问...

  • 第二章1.0初识Spring

    JDBC Template --使用了 模板模式ORM --使用了策略模式 Transaction 事务管理 ...

  • MySQL白菜教程(Level 8)

    MySQL Transaction MySQL 事务以及如何使用 COMMIT 和 ROLLBACK 语句来管理 ...

  • 数据库

    开启事务:备份。BEGIN TRANSACTION提交事务:删除备份。COMMIT TRANSACTION回滚:用...

  • mysql

    事务控制语句: BEGIN 或 START TRANSACTION 显式地开启一个事务; COMMIT 也可以使用...

  • 事务

    2.事务的语句开始事物:BEGIN TRANSACTION提交事物:COMMIT TRANSACTION回滚事务:...

网友评论

      本文标题:mongoose使用事务Transaction

      本文链接:https://www.haomeiwen.com/subject/aplysrtx.html