nodejs处理高并发问题
发布于 3 年前 作者 liuweishow 11898 次浏览 来自 问答

做了一个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);
11 回复

这时候你需要一个队列

队列跟其他后端语言的解决方案差不多,但是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 不好意思,第一次用,刚才学会了代码格式化已经重新提交。

回到顶部