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

时间:2016-09-11 10:20:24

标签: mysql node.js

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

 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;

一切正常但是有更简单的方法以更易于管理的方式编写这个可靠的查询,因为有时候有超过3-4个查询,而且代码变得复杂且不易管理。

我知道同样的事情可以通过mysql唯一索引实现但仍然如果有超过3-4个查询,在某些情况下索引将无法满足我的需求

2 个答案:

答案 0 :(得分:1)

我可以看到有两个问题。

  1. 您不能将事务与非托管池连接一起使用,因为为一个连接启动的事务无法传递给其他连接。
  2. 您获取并释放每个功能的连接。这是不必要的重复代码。
  3. 要解决这些问题,您可以通过实体使用单独的连接,例如team的一个连接,user的第二个连接等。为避免回调地狱使用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
    };
    

答案 1 :(得分:1)

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

在尝试了很多选项后,我认为最好的方式(目前在很大程度上被接受)是将babelasync/await关键字一起使用。如果您使用es2017预设,这是确保可用的一种方式。

现在,免责声明就是你仍然需要学习承诺。如果你试图跳过承诺async/await,你很快就会发现一堆没有意义的基于承诺的代码。此外,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可以更容易地进行这些类型的查询/更新。