求大神帮忙解决个嵌套跟循环查询数据库导到代码太乱的问题
发布于 10 年前 作者 pensizhangtao 6832 次浏览 最后一次编辑是 8 年前

项目用的nodejs来做 遇到一个问题求大神帮忙 查用户信息的时候因为要同时查询好几张表,所以就需要一次执行多个sql语句,这样就需要很多个嵌套函数了,还有最重要就是因为需要根据表中的每一条数据来查出相对应的数据,所以需要写出个循环来依次迭代查出的数据,并进行数据查询,实现方式 就是加了嵌套跟加了状态控制,功能虽然实现了,但是代码真是惨不忍睹!!贴出代码 dbService.psQuery(sql, [userId], function (rows) { user.userInfo = rows[0]; sql = sqls[‘user’][‘getUserPageShowList’][‘sql’]; dbService.psQuery(sql, [userId], function (rows) { user.playerList = rows; sql = sqls[‘user’][‘getUserPageActionList’][‘sql’]; /获取用户的动态信息/ dbService.psQuery(sql, [userId], function (rows) { sql = sqls[‘action’][‘getActionImgById’][‘sql’]; var lock = 0; for (var i = 0; i < rows.length; i++) { /根据动态信息来获取动态中的图集信息/ dbService.psQuery(sql, rows[i].ACTIONID, function (imgList) { if (imgList && imgList.length > 0) { rows[lock].imgList = imgList; } else { rows[lock].imgList = {}; } lock++; if (lock >= rows.length) { user.actionList = rows; /获取用户的图集信息/ sql = sqls[‘user’][‘getUserPageAlbumList’][‘sql’]; dbService.psQuery(sql, [userId], function (rows) { sql = sqls[‘album’][‘getAlbumImgById’][‘sql’]; var lock = 0; for (var i = 0; i < rows.length; i++) { dbService.psQuery(sql, rows[i].ALBUMID, function (imgList) { if (imgList && imgList.length > 0) { rows[lock].imgList = imgList; } else { rows[lock].imgList = {}; } lock++; if (lock >= rows.length) { user.albumList = rows; fn(user); } }); } });

                    }
                });
            }
        });
    });
});

小弟一直是做java开发的 刚学node 想想如果是同步执行的话的就简单多了吧 希望在大神们帮个忙能出个更好办法让这些代码解脱了啊

35 回复

async bluebird Q

不用异步,换同步不就行了。

问题 nodejs mysql的查询就是事件驱动的
connection.query(sql, values, function (err, rows) { if (err)throw err; fn(rows); }); 有同步查询的么

@tulayang 这样也不好吧 我想要那种直接可以是同步执行的效果 而且for循环的问题这个也解决不了啊

@nihgwu async 我用了 不过for循环这一块 还是解决不了 有办法让for循环执行到最后一个后自动触发一个方法么

@ngot 问题 nodejs mysql的查询就是事件驱动的 connection.query(sql, values, function (err, rows) { if (err)throw err; fn(rows); }); 有同步查询的么

@pensizhangtao

@ngot 的意思,显然让你不用Node.js,换用fibjs

@pensizhangtao

whilst循环执行完了会调用callback(err),你在回调中调用那个方法不行吗?

async.waterfall([ function(callback){ dbService.psQuery(sql, [userId], callback); }, function(rows, callback){ … dbService.psQuery(sql, [userId], callback) }, function(rows, callback){ … dbService.psQuery(sql, [userId], callback); }, function(rpws, callback){
async.forEach(rows, function(next){ async.waterfall([function(cb){ dbService.psQuery(sql, rows[i].ACTIONID,cb) }, function(imageList, cb){ … dbService.psQuery(sql, [userId], cb); }, function(imageList, cb){ … async.forEach(rows, function(next2){ dbService.psQuery(sql, rows[i].ALBUMID, function (imgList) { … next2(); }); },function(err){ cb(); }) }],function(err, results){ next(); });

       }, function(err, results){
             callback();
       })

], function (err, result) { fn(user); });

@bnuhero 大家都能解读我的意思了,哈哈

你妹,你不能写成一条SQL么?使用多结果集一次查询就能搞定了……

@hainee 我就不会写SQL查询。。

@hainee 不行 写成sql会相当乱(本来一条sql就很长而且关联很多表了)

@ngot 。 。。。这代价是不是有点高啊!

@bnuhero 因为是用的for循环 如果是while的话 我怎么才能不用状态的形式控制到最后一条数据后再执行callback 就像java的 hasNext()方法一样

@xinght 非常感谢 async.forEach(rows, function(next2){ dbService.psQuery(sql, rows[i].ALBUMID, function (imgList) { … next2(); }); next2(); 这个 函数是在循环到最后一次再执行呢 还是每次循环都会执行 想的的是 循环到最后一次再执行

@pensizhangtao 你不会用临时表么?还有SQL你没有用模版封装么?类似于IBatis那样的处理?个人表示将SQL写在代码里,代码维护鸭梨山大啊!

@hainee 这些所有的sql耦合到一块了,那我有的地方要分开用一条独立的sql,是不是还要从新写一个,另外我取数据的时候,比如我查出所有表中前4个相册的记录,并且根据相册的id,来取出相片表中所有属于此相册的相片,数据结果应该是 {相册id:1000,图片信息:{图片1:1,图片2:2,图片3:3}} 如果用一条 sql我要怎么写 查出数据后我又该怎么取呢

@pensizhangtao 有一种方法,叫引用,孩子……

@hainee 好吧!真心不懂 求大神给个例子!

@pensizhangtao 很简单,如果只是简单的一层主从关系,一张二维表就搞定了,举个很简单的例子: 1、tPhoto(相册):id, name 2、tPic(相片):id, tPhoto_id, name, pic_path 灰常简单的一句SQL: select tPic.id as PicId , tPic.tPhoto_id as PhotoId , tPic.name as pic_name as PicName , tPic.pic_path as PicPath ,tPhoto.name as PhotoName from tPic inner join tPhoto on tPic.tPhoto_id = tPhoto.id where tPhoto.id in(select top 4 id from tPhoto order by id desc);

这个查询结果序列化成JSON的格式是: //弄个变量存起来,后面给你做分组例子 var data = [ {PicId:1, PhotoId:1, PicName:“图片1”, PicPath:“图片路径1”, PhotoName:“相册1”} ,{PicId:2, PhotoId:1, PicName:“图片2”, PicPath:“图片路径2”, PhotoName:“相册1”} ,{PicId:3, PhotoId:1, PicName:“图片3”, PicPath:“图片路径3”, PhotoName:“相册1”}] //执行分组,写一个专门分组用的函数 function groupData(array, groupField) { var groupResult = {}; for (var i = 0; i < array.length; i++) { var data = array[i]; var groupValue = data[groupField]; var groupDataItem = groupResult[groupValue]; if(!groupDataItem) { groupResult[groupValue] = groupDataItem = []; groupDataItem[groupField] = groupValue; }; groupDataItem.push(data); }; return groupResult; };

var result = groupData(data, “PhotoId”);//这个result对象就是你说的{相册id:1000,图片信息:[图片1:1,图片2:2,图片3:3]},不过“图片信息”是数组对象,你可以自己修改分组函数,把这个对象改成Object,而不是Array 然后你就可以循环这个result对象来绘制你的UI了 这样处理你的数据比你在JS代码里面循环链接数据库再去查数据要快至少一个数量级:)

@pensizhangtao 每次循环都会执行 你对async的方法还是不太了解需要看看示范的例子理解下运行流程

var eventproxy = require('eventproxy');

@hainee 嗯 这种方法确实没问题 受教了!

@xinght 问题是我想要的效果是 在循环到最后一次才执行,如果是每次循环都执行的话,普通的for循环也是没问题的吧

@pensizhangtao var rows = [1,2,3,4,5] async.forEach(rows, function(next){ //模拟异步处理 setTimeout(function(){ next();//本次异步处理结束后触发下次循环执行 },5000); },function(err){ //这个方法会在循环全部执行完后被调用 也就是你说的循环最后一次才执行的地方 });

@pensizhangtao 过了好几天才看到消息提示 所以回复比较晚- -!

@xinght 运行会报错哦 next 就是相当于 rows数据中的数字 ,所以会报 数字不是一个函数无法运行 的错误 对源码又看了下 试这改成下面这个 样子,成功打印了 不过,还是对其中原理有些模糊 var async = require(‘async’); var rows = [1, 2, 3, 4, 5] async.each(rows, function (row,next) { //模拟异步处理 console.log(‘1-’ + row); next(); }, function (err) { //这个方法会在循环全部执行完后被调用 也就是你说的循环最后一次才执行的地方 console.log(‘2-1’); });

很感谢大家的帮助 @hainee 提的解决办法很对,不过这次我想好好掌握住nodejs的同步编程跟循环控制编程的技巧,现在问题已解决,贴出完整代码供大家分享,有不好的地方请大家指出(主要使用 async 来实现) var async = require(‘async’); exports.userInfo = function (userId, fn) {/信息/ var user = {userInfo: null, playerList: null, actionList: null, albumList: null}; var sql = null; async.series([function (callback) {/里面的函数信息通过 callback 依次执行/ sql = sqls[‘user’][‘getUserInfo’][‘sql’]; dbService.psQuery(sql, [userId], function (rows) { user.userInfo = rows[0]; callback(); }); }, function (callback) { sql = sqls[‘user’][‘getUserPageActionList’][‘sql’]; dbService.psQuery(sql, [userId], function (rows) { sql = sqls[‘action’][‘getActionImgById’][‘sql’]; user.actionList = rows; console.log(‘action.img.length:’ + rows.length); async.each(rows, function (row, last) {/last 函数为所有数据迭代完后 执行一次/ dbService.psQuery(sql, row.ACTIONID, function (imgList) { row.imgList = imgList; last(); }); }, function (err) {/迭代执行完毕/ callback(); }); }); }, function (callback) { sql = sqls[‘user’][‘getUserPageAlbumList’][‘sql’]; dbService.psQuery(sql, [userId], function (rows) { user.albumList = rows; sql = sqls[‘album’][‘getAlbumImgById’][‘sql’]; async.each(rows, function (row, last) {/last 函数为所有数据迭代完后 执行一次/ dbService.psQuery(sql, row.ALBUMID, function (imgList) { row.imgList = imgList; last(); }); }, function (err) { fn(user); }); }); }]); }

可以噢,北漂吧,帝都Noder待遇不错的!

@hainee 谢谢 我就是在北京! 跟公司朋友在一块很开心哦 虽然是创业公司

@pensizhangtao 工作开心那是最好了:)

@pensizhangtao 啊对 抱歉马虎了

@xinght 还是谢谢你,有你的帮助这个问题才解决的,不然我问题还闷着呢

@pensizhangtao 能帮助你我也很高兴啊 我以前一直都是个只看不说的主 如果能够帮到别人我也很高兴 共同努力学习嘛 哈哈

回到顶部