乐观锁(nodejs+mongodb)实现

1、需要锁的场景

例如:nodejs写了一个定时任务,如下:

const schedule = require('node-schedule')

schedule.scheduleJob("0 * * * * *", () => {
    runTask()
})

上述代码,每分钟执行一次 runTask 方法。

如果将上代码部署两个实例服务器上,那么实际效果是两份实例都会执行定时任务。实际上就会变成每分钟执行次。

2、乐观锁

乐观锁用于做并发的控制。大致的设计思路为:

① 设计一张乐观锁表如下:

lockNameversion
测试锁0

表中只有两个字段:锁的名字和版本号。

② 并发操作时,多个并发去抢数据库里面的锁,保证有且仅有一个能抢到锁,抢到锁的执行,其他不执行。

抢锁的规则如下:

a. 用lockName 查询出 lockName和version

b. 用lockName和version为条件去更新version (更新操作:version 加1)

c. 更新成功的即为抢到锁的。

上面的思路很精妙,一旦有个进程更新成功,其他进程手里的version就会失效,那么更新就会失败。

3、mongodb的findOneAndUpdate

利用mongodb中的findOneAndUpdate操作,findOneAndUpdate是查出符合条件的更新,这个是一个原子操作。

代码大致如下:

db.lock.findOneAndUpdate(
    { lockName: '测试锁', version: 0 },
    { $set: { version: 1 } },
)

4、node中代码实现

我们将2中的原理写出来即可。(下面代码仅保留主要功能,未对异常处理)

async function getLock(lockName) {
  const { version, lockName } = await db.lock.findOne({ lockName })
  const res = await db.lock.findOneAndUpdate(
    { lockName, version },
    { $set: { version: version + 1 } }
  )
  return res.lastErrorObject.updatedExisting
}

使用锁的时候我们下面使用,这样保证了仅仅只有一个进程能拿到锁。

const schedule = require('node-schedule')

schedule.scheduleJob("0 * * * * *", async () => {
    const lock = await getLock('测试锁')
    if (lock) {
        runTask()
    }
})

5、补充注意

需要注意的是上述的例子,仅具有思路参考性。因为上述思路的并发仅仅是限制了“同时”的情况。

实际上并发定时任务时间是存在时间差的,如果是有时间差,那么所有的执行都能先后拿到锁。此时是需要加入时间的判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三和小钢炮

谢谢客官~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值