egg icon indicating copy to clipboard operation
egg copied to clipboard

egg-mongoose 事务能否并发执行?

Open albertyou2 opened this issue 6 years ago • 1 comments

我发现在同一个接口 不同的请求加入事务后,数据更新不是每次都成功, 以下是我的服务端代码

async del(body) { const { ctx, app } = this; const session = await app.mongoose.startSession({ //readPreference: { mode: 'primary' }, }); try { const tool = new Tool(); const statusCode = new StatusCode(); let teacherNames = ''; await session.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' }, }); for (let i = 0; i < body.teacherIds.length; i++) {

    let teacher = await app.model.RoleMap.findOne({_id: body.teacherIds[i]})
    if (teacher.role.indexOf("master") >= 0 || teacher.role.indexOf("admin") >= 0) {//  
      teacher = await app.model.RoleMap.findOneAndUpdate(
        { _id: body.teacherIds[i] },
        { $pull : { role : "teacher" }},
        { new: true, session :session }
      );
    }else{
      teacher = await app.model.RoleMap.findOneAndUpdate(
        { _id: body.teacherIds[i] },
        { state: 'deleted'},
        { new: true,session :session}
      );
    }
 
    const classes = await app.model.Class.find({teachers: body.teacherIds[i]});
    for (let j = 0; j < classes.length; j++) {
      let teachers = e.teachers;
      teachers = teachers.slice(j, 1);
      await app.model.Class.updateOne({_id: e._id}, {teachers},{ session });
    }
    if (body.teacherIds.length > 1) {
      teacherNames += `、${teacher.name}`
    } else {
      teacherNames = teacher.name;
    }
  }
  const admins = await app.model.RoleMap.find({
    role: {$in: ['admin', 'master']},
    state: 'available',
    school: body.school
  })
  const operator = await app.model.RoleMap.findOne({
    phone: body.phone,
    school: body.school
  })
  const msg = `已成功删除${teacherNames}老师信息`
  admins.forEach(e => {
    tool.pushMsg(String(e.teacher), msg)
  })
  await app.model.NotifyMsg.create([{
    title: '删除通知',
    // 消息内容
    content: msg,
    // 处理人
    operator: operator._id,
    // 消息种类,删除: del, 续费:pay,报名:regist,奖学金:reward, 课程: course, 签到:sign,
    // 点评: comment, 作业:homework,课时费: courseFee, 请假: dayOff, sticker: sticker
    kind: 'del',
    // 消息类型: 管理员端: admin, 老师端: teacher, 家长端:parent
    type: 'admin',
    school: body.school
  }],{session});

  await session.commitTransaction(); // 提交事务
  return statusCode.success;
} catch(err) {
  await session.abortTransaction(); // 回滚
  app.logger.error(`\x1B[41;37m ERROR: TeacherService,del \x1B[0m ${err}---${err.stack}`);
  return { code: 500, msg: 'server error', result: false };
}finally{
  await session.endSession(); // 结束
}

}

########### 测试代码如下 test.js // 模拟同时删除两个不同的老师 var fs = require('fs'), request = require('request'); //var host = 'localhost';

var host = 'edu.brmind.cn' var opt = { method:'POST', url:https://${host}/api/role/del, json:true, body: {"teacherIds":["5d3d067ce4a51b0394b89b7b"]}, }

var opt1 = { method:'POST', url:https://${host}/api/role/del, json:true, body: {"teacherIds":["5d3d08a1fff42c04d641ebda"]}, }

// 请求 0 request(opt,(err,res,body)=>{ if(err){ console.log(err); return; } console.log(body); console.log(res.headers); }); // 请求 1 request(opt1,(err,res,body)=>{ if(err){ console.log(err); return; } console.log(body); console.log(res.headers); });

我发现,又时候能成功删除一个老师,又时候2个都删不掉, 是否我的用法又问题,mongoose有相关的设置我没用对? 谢谢解答

相关环境信息

  • 操作系统:centos 7
  • Node 版本: v11.14.0
  • Egg 版本: 2.21.1

albertyou2 avatar Jul 28 '19 03:07 albertyou2

mongoose 能怎么样就怎么样,egg 只是简单的一个包装,可以看下对应的 mongoose 类库去。

PS:学会用 Markdown 的 code 排版

atian25 avatar Jul 28 '19 03:07 atian25