Nodejs 怎么避免并发修改同一条数据
Nodejs 怎么避免并发修改同一条数据
有个功能大致如下,在一堆没用过的数据中取一条数据,并将其标示为已用,nodejs要怎么才能把一块代码或一个函数设为不能同步执行,类似于java的synchronized,谢谢。
要避免在 Node.js 中并发修改同一条数据,可以使用锁机制来确保同一时间只有一个进程或线程能够访问和修改该数据。在 Node.js 中,可以使用一些库来实现这种锁机制,比如 async-mutex
或者 redis
(如果需要分布式锁)。
以下是一个使用 async-mutex
库的示例代码,来展示如何避免并发修改同一条数据:
- 首先,安装
async-mutex
库:
npm install async-mutex
- 然后,编写代码来实现锁机制:
const { Mutex } = require('async-mutex');
// 创建一个互斥锁实例
const mutex = new Mutex();
// 模拟数据库中的数据
let unusedData = [
{ id: 1, used: false },
{ id: 2, used: false },
{ id: 3, used: false }
];
// 函数用于从未使用的数据中取出一条并标记为已使用
async function takeUnusedData() {
// 获取锁
const release = await mutex.acquire();
try {
// 查找第一条未使用的数据
const index = unusedData.findIndex(data => !data.used);
if (index !== -1) {
// 将找到的数据标记为已使用
unusedData[index].used = true;
console.log(`Taken data: ${JSON.stringify(unusedData[index])}`);
} else {
console.log('No unused data available.');
}
} finally {
// 释放锁
release();
}
}
// 模拟并发调用
Promise.all([
takeUnusedData(),
takeUnusedData(),
takeUnusedData()
]).then(() => {
console.log('All operations completed.');
});
在这个示例中,我们使用了 async-mutex
库创建了一个互斥锁 (mutex
)。每次调用 takeUnusedData
函数时,都会尝试获取锁。只有当锁被当前进程获取时,才会执行查找和修改数据的操作。其他进程在等待锁释放之前不会执行相同的操作,从而避免了并发修改同一个数据的问题。
通过这种方式,我们可以确保在同一时间只有一个进程能够修改数据,从而避免并发问题。
mysql, oracle…? 用事务啊 redis? 大部分情况不需要你处理原子性 memcache? cas就可以
能说的详细点吗,我是担心两个请求同时取到同一条记录
是mysql,我是担心两个请求同时取到同一条记录,这个应该跟事务没关系吧
node.js的编程模型是单线程异步IO,从这个角度来说,应该不会出现你说的问题。
node 基于数据库的操作,或者第三方模块,都是用回调的方式调用异步的。node也是单线程异步io,所以在同一时间里是不可能有两个或多个io同时工作,所谓单线程并发其实也就是串行执行的,只不过减少了cpu等待,提高了cpu的系统吞吐量
-
不知道楼主的意思是不是由于 Node.js 的单线程模型所以不是问题。比如当某个函数中没有异步代码时,这时,这个函数一定会独占 CPU 直到执行完毕。
-
也可能楼主遇到的问题在 Node.js 的单线程中也可能发生。比如在函数中出现了异步调用。
我读取数据的方法就是在回调函数里面执行的,大致如下:
function(err, cb) {
...
executeOneFunc(err, function(err){ //执行某个函数
readData(function(err, data) { //读取数据
checkData(); //检查数据
updateData(data, function(err){ //修改数据
doOther();//执行其他的操作
});
});
});
...
}
这样子也不用担心同步问题吗,我刚接触nodejs不久,所以问的比较初级,请见谅。
谢谢,实际情况我在下面做了回复,那种情况是不是也不用担心。
谢谢,实际情况我在下面做了回复,那种情况是不是也不用担心。
谢谢,实际情况我在下面做了回复,那种情况是不是也不用担心。
你这样写妥妥的有问题…
你checkdata 里面是异步操作吧…不要少嵌套了…
建议用async…
额。。这时需要担心的。我暂时没有解决方案。
既然用的mysql,那很简单吧,增加一个字段表示处理过没有(或者已有字段能表示也行),updateData的时候,类似下面的伪代码逻辑: update a=1 b=2 flag=1 where flag==0 && id=xxx 原子性由sql语句自己保证。
好像我看到update的时候,只会返回affectedRows,能得到update的那条记录的id吗。因为获取到的数据还要修改关联的其他数据,如果其他数据修改失败,那这个update也要回滚,整个是处于事务的
把这种功能抽出来,单独部署. 然后其他节点统一通过这个模块来操作
var proxy = new EventProxy(); var status = “ready”; var select = function (callback) { proxy.once(“selected”, callback); if (status === “ready”) { status = “pending”; db.select(“SQL”, function (results) { proxy.emit(“selected”, results); status = “ready”; }); } };
为了避免在 Node.js 中并发修改同一条数据,可以使用锁机制来确保同一时间只有一个进程能够修改该数据。Node.js 没有内置的锁机制,但可以借助第三方库来实现。例如,可以使用 async-mutex
库来创建互斥锁。
以下是一个简单的示例代码:
const { Mutex } = require('async-mutex');
const mutex = new Mutex();
async function markAsUsed(dataList) {
const release = await mutex.acquire();
try {
// 查找未使用的数据并标记为已使用
const unusedData = dataList.find(item => !item.used);
if (unusedData) {
unusedData.used = true;
console.log('Marked as used:', unusedData);
} else {
console.log('No unused data found.');
}
} finally {
release();
}
}
// 示例数据
const dataList = [
{ id: 1, used: false },
{ id: 2, used: false },
{ id: 3, used: false }
];
// 并发调用
Promise.all([
markAsUsed(dataList),
markAsUsed(dataList),
markAsUsed(dataList)
]).then(() => {
console.log('All done.');
});
在这个示例中,mutex
是一个互斥锁,它确保 markAsUsed
函数在同一时间只能被一个进程执行。通过 await mutex.acquire()
获取锁,并在操作完成后通过 release()
释放锁。
如果希望避免数据竞争条件,还可以考虑使用数据库事务来确保原子性操作。例如,使用 PostgreSQL 的 BEGIN
, COMMIT
和 ROLLBACK
语句来确保事务的完整性。
这种方法能有效避免多个请求同时修改同一条数据的情况,从而保证数据的一致性和完整性。