做了一个nodejs并发测试,先描述一下环境 数据库mysql,大概两张表,读取第一张表test的数据,拿出来-1,存到第二张testlog表记录一下,用jmeter同事模拟50个请求,结果发现,部分数据没有-1成功
test 表数据
id num desc
1 94 2017-02-28 14:41:17:86
testlog 表数据
id, testid, num, desc
4 1 99 2017-02-28 14:32:42:28
5 1 98 2017-02-28 14:32:43:76
6 1 97 2017-02-28 14:32:44:89
7 1 97 2017-02-28 14:32:44:88
8 1 97 2017-02-28 14:32:44:28
9 1 97 2017-02-28 14:32:44:86
10 1 97 2017-02-28 14:32:44:45
11 1 97 2017-02-28 14:32:45:48
12 1 97 2017-02-28 14:32:45:49
推测可能是同时修改数据,某一个现在没有修改完毕,下一个线程已经读取过了,导致数据更新不一致,但是nodejs不都是单线程的吗,请各位大神解析一下,谢谢
代码如下
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function (req, res) {
res.writeHead(200, {
"Content-Type": "text/html;charset=utf-8"
});
res.end("OK");
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'myData'
});
connection.connect();
connection.query('SELECT * from test', function (err, rows, fields) {
if (err) {
console.log(err);
return;
};
var test = rows[0]; //读取num
var num = test.num - 1;
var id = test.id;
connection.query("update test set num=" + num + ",`desc`='" + dateFormat(new Date()) + "'", function (err, res) {
if (!err) {
var insert = "insert into testlog(testid,num,`desc`) values ('" + id + "','" + num + "','" + dateFormat(new Date()) + "')";
connection.query(insert, function (err, res) {
if (!err) {
connection.end();
console.log("update sucess!");
} else {
console.log(err);
}
});
} else {
connection.end();
console.log(err);
}
});
});
function dateFormat(date) {
var fmt = "yyyy-MM-dd hh:mm:ss:SS";
var o = {
"M+": date.getMonth() + 1, //??
"d+": date.getDate(), //?
"h+": date.getHours(), //С?
"m+": date.getMinutes(), //?
"s+": date.getSeconds(), //?
"q+": Math.floor((date.getMonth() + 3) / 3), //??
"S+": date.getMilliseconds() //?ī
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
}
}).listen(3000);
这时候你需要一个队列
队列跟其他后端语言的解决方案差不多,但是nodejs不是号称单线程事件驱动吗?那这样是不是说明可以同时接受多个用户的请求?
var test = rows[0];
你这么写,鬼知道你改的哪个?
@coordcn 读取rows[“num”]
@liuweishow 本来就是能同时接受多个用户请求的,单线程不是给你把http请求排成队列一个一个处理,举个例子:a请求到达->a请求查询数据库(异步,直接往下走)->b请求到达->b请求查询数据库, 所以完全有可能处理a请求的数据库查询异步操作时,还没走到回调,b请求又来了,这时候b请求查询数据库得到的结果是和上一次一样的
@hyj1991 好的,谢谢大神清晰明了的解释。下次遇到单个资源多个用户抢占的时候还是老老实实的用redis锁吧
@liuweishow redis里面的setnx确实做锁挺不错的,其实这些外部资源和语言无关的,处理方式都是类似。js单线程只是不需要开发者去考虑 锁变量 的场景,但是 锁资源 大家都是一样的。
实在看不下去了,本来还想分析一下,这个排版。。。摸着良心说,你自己愿意看第二遍吗?帖子发出来前,点下预览自己看下好不。
这排版。溜了溜了
@haozxuan 不好意思,第一次用,刚才学会了代码格式化已经重新提交。
@wocaatm 不好意思,第一次用,刚才学会了代码格式化已经重新提交。