意图返回之前循环返回的NodeJS MySQL查询

时间:2018-11-20 05:14:02

标签: javascript mysql node.js

我正在尝试创建一个函数,该函数将生成4个唯一的ID(十六进制)以插入到我的数据库中。我将查询放在do while循环中以检查是否存在冲突,如果代码已经存在,则重新生成代码,如果不存在,则返回值。

问题在于循环会在预期之前退出。例如,如果生成了代码“ a”但已经在数据库中显示了该代码,则将重新生成该代码,但是循环将退出,并且永远不会进行新的查询。新代码不会返回-而是返回生成的第一个代码。

这是我的代码:

const FIND_EXISITNG_COURT =
  "SELECT access_code,team1,team2 FROM courts WHERE access_code= ?";

function generateAccessCode() {

  var random = Math.floor(Math.random() * (+30 - +0)) + +0;
  var code = random.toString(16);

  var hasDupe = false;

  do {
      connection.query(FIND_EXISITNG_COURT, [code], (err, results) => {

          if (err) {
              throw err;
          } else if (results.length > 0) {
              random = Math.floor(Math.random() * (+30 - +0)) + +0;
              code = random.toString(16);

              hasDupe = true;
          } else {
              hasDupe = false;
          }
      });
  } while (hasDupe);

  return code;
}

我是NodeJS的新手,所以我不知道这样做是否不好。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:0)

在您的代码中,query的回调函数将在数据准备好后稍后运行,因此hasDupe将在第一时间为false,并返回生成的代码。 / p>

您可以使用Promiseasync函数来解决您的问题

const FIND_EXISITNG_COURT =
"SELECT access_code,team1,team2 FROM courts WHERE access_code= ?";

function selectByCode(code) {  
    return new Promise((resolve, reject) => {
        connection.query(FIND_EXISITNG_COURT, [code], (err, results) => {
        if (err) {
            reject(err);
        } else {
            resolve(results.length)
        }
    });
}

async function generateAccessCode() {

    var random = Math.floor(Math.random() * (+30 - +0)) + +0;
    var code = random.toString(16);

    var hasDupe = false;

    let count =0;
    try{
        do {

            count = await selectByCode(code);
            if (count > 0) {
                random = Math.floor(Math.random() * (+30 - +0)) + +0;
                code = random.toString(16);

                hasDupe = true;
            } else {
                hasDupe = false;
            }


        } while (hasDupe);

        return code;
    }
    catch(e){
        throw e;

    }
}

答案 1 :(得分:0)

您对connection.query的调用是异步的,这意味着您定义的回调不会立即运行。您的代码只注册了该回调,然后继续执行直到generateAccessCode结束。直到很久以后(数据库返回某些内容时),回调才被调用,因此hasDupe仅在原始函数已经退出后很长时间才被设置。

您基本上有3个选项来处理此问题:回调,promise或async / await(实际上只是在promises之上的语法糖)。

使用async / await的示例,但尝试尽可能保持与原始结构的距离(多次运行以使其正常工作):

// this is a mock for the db call. This "database" already holds records with IDs 0, 2 and 3.
// IRL you will need to wrap your db call in a function that returns a promise
// if you want to do it this way
const connectionQuery = function (code) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(code === 1 ? [] : [true]), 1000);
  });
}

async function generateAccessCode() {
  // simplified the code generation for this example
  let code = Math.floor(Math.random() * 4); // Code can be 0, 1, 2, or 3

  let hasDupe = false;
  let results;
  do {
      results = await connectionQuery(code); // await here is the key
      if (results.length > 0) {
        console.log(`Code ${code} already exists in the database. Generating new code...`);
        code = Math.floor(Math.random() * 4);           
        hasDupe = true;
      } else {
        hasDupe = false;
      }      
  } while (hasDupe);

  return code;
}

generateAccessCode()
  .then((code) => {
    console.log(`Final result: ${code}`);
  })
  .catch((err) => {
    console.log(err);
  });

使用回调:

// this is a mock for the db call. This "database" already holds records with IDs 0, 2 and 3.
const connectionQuery = function (code, callback) {
  setTimeout(() => {    
    callback(null, code === 1 ? [] : [true]);
  }, 1000);
}

function generateAccessCode(callback) {
  // simplified the code generation for this example
  let code = Math.floor(Math.random() * 4); // Code can be 0, 1, 2, or 3

  let hasDupe = false;
  let results;
  
  connectionQuery(code, (err, results) => {
    if (err) {
      return callback(err);
    }
  
    if (results.length) {
      console.log(`Code ${code} already exists in the DB`);
      return generateAccessCode(callback);
    }
    
    callback(null, code);
  });
}

generateAccessCode((err, code) => {
  console.log(`Final result: ${code}`);
});