You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sequelize事务运行异常,findOne无法获取最新数据是否需要加锁?

问题解答

事务执行逻辑说明

Sequelize不会自动对事务做串行处理,每次调用sequelize.transaction()生成的都是独立的数据库事务,多个事务会并行在数据库层执行,不存在默认串行的逻辑。

问题根因

你遇到的findOne读取不到最新值的问题,是典型的并发事务读写竞争问题:默认的事务隔离级别下,并行执行的事务无法读取到其他事务未提交的修改,多个请求同时发起查询时,会同时拿到同一个还没满员的房间,后续都往这个房间加人,最终导致人数超出上限。

修复方案

不需要引入额外的分布式锁,直接用Sequelize自带的查询行级锁即可解决,修改你代码中的findOne查询逻辑,加排他锁阻塞其他并行事务的查询,直到当前事务提交后其他事务才能读取最新数据:

// 首先从sequelize引入Transaction
const { Transaction } = require('sequelize');

const test_create_transaction = async (serviceID, res) => {
  try {
    return sequelize.transaction(async (t) => {
      let serviceRoom;
      // Find a service room with less than a certain number of customers
      serviceRoom = await ServiceRooms.findOne({
        where: {
          serviceID,
          numberCustomers: {
            [Op.lt]: MAX_CUSTOMERS_PER_ROOM,
          },
        },
        transaction: t,
        // 新增行级更新锁,当前事务释放前其他事务无法修改或查询匹配的记录
        lock: Transaction.LOCK.UPDATE,
      });
      // If no such room exists, create a new room
      if (!serviceRoom) {
        serviceRoom = await ServiceRooms.create(
          {
            serviceID,
          },
          { transaction: t }
        );
      }
      const testUserUID = "testUID" + Date.now().toString();
      const { serviceRoomUID } = serviceRoom;
      // Add the customer to that room
      await ServiceRoomEnrollments.create(
        {
          serviceRoomUID: serviceRoomUID,
          userUID: testUserUID,
          serviceID: serviceID,
        },
        { transaction: t }
      );
      // Increment the number of customers in that room
      await ServiceRooms.increment("numberCustomers", {
        by: 1,
        transaction: t,
        where: {
          serviceRoomUID: serviceRoomUID,
        },
      });
      return res.send("test");
    });
  } catch (error) {
    console.log("error: ", error.message);
    res.end();
  }
};

额外优化建议

  • 可以在数据库层为ServiceRooms表的numberCustomers字段添加检查约束,确保数值永远不会超过MAX_CUSTOMERS_PER_ROOM,作为兜底校验避免代码逻辑漏洞
  • 如果业务并发量极高,也可以考虑将房间分配逻辑放到数据库存储过程中执行,进一步降低网络交互带来的竞争窗口

内容的提问来源于stack exchange,提问作者dev_jeo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 22:18:03