我正在尝试创建一个函数,该函数将生成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的新手,所以我不知道这样做是否不好。任何帮助将不胜感激!
答案 0 :(得分:0)
在您的代码中,query
的回调函数将在数据准备好后稍后运行,因此hasDupe
将在第一时间为false
,并返回生成的代码。 / p>
您可以使用Promise
和async
函数来解决您的问题
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}`);
});