在nodejs中执行多个可靠的mysql查询

我正在一个项目中,我必须为用户创build团队,但在此之前,我需要检查该团队名称是否已被同一用户占用。下面是示例代码

var mysql=require('../../config/mysql_connect.js'); var dateFormat = require('dateformat'); var functions={ createTeam:function(data,cb){ this.checkifExists(data,function(err,result){ if(err) { cb(err); } else { if(result.length) { cb(null,0); // Team name exists } else { mysql.getConnectionFromPool(function(err,con){ if(err) { cb(err); } else { var query=con.query("Insert into team SET ? ",data,function(err,result){ if(err) { cb(err); } else { cb(null,result.insertId); } con.release(); }); } }); } } }); }, checkifExists:function(data,cb){ mysql.getConnectionFromPool(function(err,con){ if(err) { cb(err); } else { var sql="Select id from team where user_id = ? and team_name like "+ con.escape('%'+data.team_name+'%') ; var query=con.query(sql,[data.user_id,data.team_name],function(err,result){ if(err) { cb(err); } else { cb(null,result); } con.release(); }); console.log(query.sql); } }); } }; module.exports=functions; 

一切正常,但有没有更容易的方式来写这个可靠的查询以更易于pipe理的方式,因为有时候有超过3-4个查询和代码变得复杂和不可pipe理。

我知道同样的事情可以通过MySQL独特的索引来实现,但如果有更多的3-4个查询,并且在某些情况下索引不能满足我的需求

我可以看到有两个问题。

  1. 您不能使用与非托pipe池连接的事务,因为为一个连接启动的事务无法传递给其他连接。
  2. 你得到并释放每个函数的连接。 这是不必要的重复代码。

要解决这些问题,您可以使用单独的连接通过实体,例如一个team连接,第二个user和更多。 为了避免callback地狱使用async模块或承诺。

这是草稿

 // db.js var mysql=require('../../config/mysql_connect.js'); var connections = {}; // No, that code don't solve problems, because transaction can't started inside other. // Block mechanism by transaction property `is_busy` seems a bulky. function DB(name) { if (!name) // unnamed connection. Must be released on query end. return mysql.getConnectionFromPool(); if (!connections[name]) // create always open connection connections[name] = mysql.getConnectionFromPool(); return connections[name]; } module.exports = DB; // team.js var dateFormat = require('dateformat'); var async = require('async'); var db = require('db')('team'); // get always-open connection for team-entity from pool function create (data, cb) { // Here async is not necessary but used as example async.waterfall([ function(cb) { isExists(data.user_id, data.team_name, cb); }, function(isTeamExists, cb) { if (!isTeamExists) return cb(); // go to end of waterfall // is a bad statement; use enum of fields db.query('insert into team SET ?', data, cb); }], // end waterfall chain function(err, team_id) { if (err) return cb(err); // pass error to original cb-func ...do-smth and call cb without error... } ); } function isExists (user_id, team_name, cb) { // You can use ?? to masked input db.query('select 1 from team where user_id = ?? and team_name like "%??%"', [user_id, team_name], function(err, res) { cb(err, !err && res.length > 0); } ); } module.exports = { create, isExists }; 

这是每个人都使用JavaScript的基本问题。 多年来,我尝试了很多不同的方法来解决这个问题。

在尝试了很多select之后,我认为最好的方式(目前被广泛接受)是使用babelasync/await关键字。 如果您使用es2017预设是确保可用的一种方法。

现在免责声明是,你仍然必须学习承诺。 如果你试图跳过承诺async/await你会很快find一堆基于承诺的代码,没有任何意义。 此外, async/await需要承诺..所以你需要教你自己。 习惯它将需要一些时间。

另一个可以帮助一般JavaScript的事情是使用两个空格,而不是四个或一个选项卡。 这确实使您的代码更具可读性。 另外,把你的开放花括号放在同一行,不要在任何地方添加额外的空白行,只有在需要使代码易于阅读的地方。

所以,这不是确切的代码,而是我将如何做的一个概要:

 async function existsTeam(data) { const id = await query('select id ..', data); return id; } async function createTeam(data) { const existingId = await existsTeam(data); if (existingId) return existingId; const result = await query('insert into team ..', data); return result.insertId; } 

对于MySQL的具体情况,你试图强制一个约束,我认为MySQL不支持在数据库上的外键约束 – 但你可以仔细检查,因为如果这样做可以简化事情。 但是使用Sequelize或Bookshelf ORM,这些types的查询/更新可能更容易。