NodeJS await / async с вложенным MySQL-запросом - PullRequest
0 голосов
/ 27 декабря 2018

Мне нужна помощь по поводу этого кода:

var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";

async function checkIfUserCodeExist() {
  connection.promise().query(sqlCheckIfExist)
    .then(([rows, fields]) => {
    if (rows == 0) {
      console.log("Non esiste!")
      return res.send(JSON.stringify({
        "status": 500,
        "response": "codeNotExist"
      }));
    }
    checkIfCodeIsSameAsMine()
    console.log("Esiste!")
    console.log(rows[0].my_refer);
  })
    .catch(console.log)
    .then(() => connection.end());
}

async function checkIfCodeIsSameAsMine() {
  connection.promise().query(sqlCodeCheckSameAsMine)
    .then(([rows, fields]) => {
    if (rows == friendReferCode) {
      console.log("Codice uguale!")
      return res.send(JSON.stringify({
        "status": 500,
        "response": "sameCodeAsMine"
      }));
    }
    console.log("Codice non uguale!")
  })
    .catch(console.log)
    .then(() => connection.end());
}

checkIfUserCodeExist()

Я устанавливаю соединение следующим образом:

app.use(function(req, res, next) {
  global.connection = mysql.createConnection({
    host: 'xx',
    user: 'xx',
    password: 'xx',
    database: 'xx'
  });
  connection.connect();
  next();
});

Я не могу понять одну вещь: Как я могу назвать вложеннымзапрос?Когда я проверяю, есть ли строки == 0 в функции checkIfUserCodeExist (), если она ложная, я вызываю checkIfCodeIsSameAsMine (), но я получаю эту ошибку:

Error: Can't add new command when connection is in closed state
at Connection._addCommandClosedState (/usr/myserver/node_modules/mysql2/lib/connection.js:135:17)
at Connection.end (/usr/myserver/node_modules/mysql2/lib/connection.js:836:26)
at connection.promise.query.then.catch.then (/usr/myserver/addReferFriend.js:45:31)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)

Как я могу это исправить?

Я выкладываю полный файл здесь:

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.post('/', function(req, res, next) {
    var uid = req.body.uid;
    var friendReferCode = req.body.friendReferCode;

    var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";
async function checkIfUserCodeExist() {
    connection.promise().query(sqlCheckIfExist)
    .then( ([rows,fields]) => {
            if (rows == 0) {
                console.log("Non esiste!")
                return res.send(JSON.stringify({"status": 500,"response": "codeNotExist"}));
            }
            checkIfCodeIsSameAsMine()
            console.log("Esiste!")
            console.log(rows[0].my_refer);
    })
    .catch(console.log)
    .then( () => connection.end());
    }

    async function checkIfCodeIsSameAsMine() {
        connection.promise().query(sqlCodeCheckSameAsMine)
        .then( ([rows,fields]) => {
                if (rows == friendReferCode) {
                    console.log("Codice uguale!")
                    return res.send(JSON.stringify({"status": 500,"response": "sameCodeAsMine"}));
                }
                console.log("Codice non uguale!")
        })
        .catch(console.log)
        .then( () => connection.end());
        }

checkIfUserCodeExist()
});

module.exports = router;

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 27 декабря 2018

У вас есть несколько проблем в вашей программе, которые вы должны обновить.

Прежде всего, вы не должны использовать глобальную переменную для хранения соединения с базой данных по запросу.Если два запроса поступают одновременно, тогда один запрос перезапишет connection других созданных запросов, поэтому вы можете использовать одно и то же соединение для обоих запросов и / или не закрывать одно из соединений, что приводит коборванное соединение, которое в худшем случае может привести к тому, что ваше приложение не отвечает.

Чтобы решить эту проблему, вам нужно передать соединение с объектом запроса:

app.use(async function(req, res, next) {
  try {
    if( req.dbConnection ) {
      // ensure that req.dbConnection was not set already by another middleware
      throw new Error('req.dbConnection was already set')
    }

    let connection = mysql.createConnection({
      host: 'xx',
      user: 'xx',
      password: 'xx',
      database: 'xx'
    });

    res.on("finish", function() {
      // end the connection after the resonponse was send
      req.dbConnection.end()
    });

    // assign a promise base version of connection to request
    req.dbConnection = connection.promise()

    // wait for the connection to be established
    await connection.connect();
    next();
  } catch(err) {
    next(err);
  }
});

Для доступа к определенному запросуДля соединения вы должны сделать что-то вроде этого:

app.get('/', async function(req, res, next) {
   try {
     await checkIfUserCodeExist(req.dbConnection)

     // so something here after `checkIfUserCodeExist` finished
   }  catch(err) {
     next(err); // if an error occured pass it to the next
   }
})

async можно использовать с await, если в вашем теле функции нет await, тогда вам не нуженasync перед функцией.

Если у вас нет await в теле функции, вам нужно вернуть цепочку Promise из функции, чтобы вызывающая сторона могла дождаться завершения функции:

function checkIfUserCodeExist(connection) {
  return connection.query(sqlCheckIfExist)
    .then(([rows, fields]) => {
      if (rows == 0) {
        console.log("Non esiste!")

        return res.send(JSON.stringify({
          "status": 500,
          "response": "codeNotExist"
        }));
      }
      console.log("Esiste!")
      console.log(rows[0].my_refer);
      return  checkIfCodeIsSameAsMine(connection)
    })
}

function checkIfCodeIsSameAsMine(connection) {
  return connection.query(sqlCodeCheckSameAsMine)
    .then(([rows, fields]) => {
      if (rows == friendReferCode) {
        console.log("Codice uguale!")
        return res.send(JSON.stringify({
          "status": 500,
          "response": "sameCodeAsMine"
        }));
      }
      console.log("Codice non uguale!")
    })
}

Если вы хотите использовать async, это будет выглядеть так:

async function checkIfUserCodeExist(connection) {
  let [rows, fields] = await connection.query(sqlCheckIfExist)

  if (rows == 0) {
    console.log("Non esiste!")
    return res.send(JSON.stringify({
      "status": 500,
      "response": "codeNotExist"
    }));
  }

  await checkIfCodeIsSameAsMine()

  console.log("Esiste!")
  console.log(rows[0].my_refer);
}

async function checkIfCodeIsSameAsMine(connection) {
  let [rows, fields] = await connection.query(sqlCodeCheckSameAsMine)

  if (rows == friendReferCode) {
    console.log("Codice uguale!")
    return res.send(JSON.stringify({
      "status": 500,
      "response": "sameCodeAsMine"
    }));
  }

  console.log("Codice non uguale!")
}

Вы бы избежали чего-то вроде:

return res.send(JSON.stringify({
  "status": 500,
  "response": "codeNotExist"
}));

Вместоиз этого вы бы выдавали пользовательскую ошибку вроде:

throw new CustomError(500, "codeNotExist")

и имели бы промежуточное ПО для ошибки:

app.use(function(err, req, res, next) {
  return res.send({
    "status": err.status,
    "response": err.message
  });
})

Таким образом, у вас есть только одно место, где вы создаете ответ об ошибке, и вы можете создатьпри необходимости вносит изменения в этот ответ об ошибке, например, добавляет дополнительное ведение журнала.

РЕДАКТИРОВАТЬ (в соответствии с обновленным вопросом)

/* GET users listing. */
router.post('/', function(req, res, next) {
  var uid = req.body.uid;
  var friendReferCode = req.body.friendReferCode;

  var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
  var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";

  function checkIfUserCodeExist() {
    return req.dbConnection.query(sqlCheckIfExist)
      .then(([rows, fields]) => {
        if (rows == 0) {
          console.log("Non esiste!")

          return res.send(JSON.stringify({
            "status": 500,
            "response": "codeNotExist"
          }));
        }
        console.log("Esiste!")
        console.log(rows[0].my_refer);
        return checkIfCodeIsSameAsMine(connection)
      })
  }

  function checkIfCodeIsSameAsMine() {
    return req.dbConnection.query(sqlCodeCheckSameAsMine)
      .then(([rows, fields]) => {
        if (rows == friendReferCode) {
          console.log("Codice uguale!")
          return res.send(JSON.stringify({
            "status": 500,
            "response": "sameCodeAsMine"
          }));
        }
        console.log("Codice non uguale!")
      })
  }

  checkIfUserCodeExist()
   .catch(next)
});
0 голосов
/ 27 декабря 2018

Хорошо, в вашем коде много проблем.Я начну с рассмотрения вашего конкретного вопроса, а затем дам несколько дополнительных советов.:)

Ваша проблема заключается в этой логике:

connection.promise().query(sqlCheckIfExist)
    .then(([rows, fields]) => {
    // some code 

    checkIfCodeIsSameAsMine()

   // some code
  })
    .catch(console.log)
    .then(() => connection.end());

Функция checkIfCodeIsSameAsMine() является асинхронной.Итак, в этой цепочке кода происходит то, что вы вызываете checkIfCodeIsSameAsMine(), но вы не ждете его результата и сразу переходите к последнему then(), в котором вы закрываете соединение с БД.Итак, по сути, код, который выполняется в checkIfCodeIsSameAsMine(), выполняется после , когда вы закрываете соединение.

Вы должны return checkIfCodeIsSameAsMine().Таким образом, вы будете ждать ответа Promise от этой функции.

Теперь к моим дополнительным точкам.

Во-первых, "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'"; равно ПЛОХО .Вы подвергаете свое приложение таким уязвимостям, как внедрение SQL.Вы должны экранировать динамические значения в запросе SQL через некоторые функции синтаксического анализа.Обычно это делается с помощью ORM (connection(), который вы используете).

Во-вторых, если вы используете функции async, тогда используйте соответствующие функции await.Как это:

async function checkIfUserCodeExist() {
  let rows, fields;

  try {
    [rows, fields] = await connection.promise().query(sqlCheckIfExist);
  } catch (err) {
    console.log(err);
  }
  if (rows == 0) {
    console.log("Non esiste!");
    return res.send(JSON.stringify({
      "status": 500,
      "response": "codeNotExist"
    }));
  }
  console.log("Esiste!");
  console.log(rows[0].my_refer);

  let result;
  try {
    result = await checkIfCodeIsSameAsMine();
  } catch (err) {
    console.log(err);
  }

  // do something with "result" if you wish

  await connection.end();
}
0 голосов
/ 27 декабря 2018

Это может произойти из-за того, что вы разрываете соединение в конце функции checkIfUserCodeExist . Удалите следующую строку, и я думаю, что она будет работать:

connection.end()

ИЛИ если вы хотите открывать и закрывать ее каждый раз, когда вы можете создать метод, вернете новое соединение и вызоветеэто перед выполнением любых запросов к БД.пример:

 function getMysqlConnection() {
     const connection = mysql.createConnection({
         host: 'xx',
         user: 'xx',
         password: 'xx',
         database: 'xx'
     });
     connection.connect();
     return connection;
 }

 var sqlCheckIfExist = "SELECT my_refer FROM hub_user WHERE my_refer = '" + friendReferCode + "'";
 var sqlCodeCheckSameAsMine = "SELECT my_refer FROM hub_user WHERE uid = '" + uid + "'";
 async function checkIfUserCodeExist() {
     const connection = getMysqlConnection();
     connection.promise().query(sqlCheckIfExist)
         .then(([rows, fields]) => {
             if (rows == 0) {
                 console.log("Non esiste!")
                 return res.send(JSON.stringify({ "status": 500, "response": "codeNotExist" }));
             }
             checkIfCodeIsSameAsMine()
             console.log("Esiste!")
             console.log(rows[0].my_refer);
         })
         .catch(console.log)
         .then(() => connection.end());
 }

 async function checkIfCodeIsSameAsMine() {
     const connection = getMysqlConnection();
     connection.promise().query(sqlCodeCheckSameAsMine)
         .then(([rows, fields]) => {
             if (rows == friendReferCode) {
                 console.log("Codice uguale!")
                 return res.send(JSON.stringify({ "status": 500, "response": "sameCodeAsMine" }));
             }
             console.log("Codice non uguale!")
         })
         .catch(console.log)
         .then(() => connection.end());
 }

 checkIfUserCodeExist()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...