在 MySQL 上使用 Promise 进行并行插入查询失败
Using Promise for parallel insert query on MySQL fails
我为 运行 在 Node.js 中并行插入查询编写了代码,我也在使用 Promise.js。
但是代码失败并引发了 "Duplicate Primary Key" 条目的异常。
代码如下,
var Promise = require("promise");
var mySql = require("mysql");
var _ = require("underscore");
var connection = mySql.createConnection({
host : "localhost",
user : "root",
password : "rahul",
database : "testDb" //schema
});
connection.connect();
function insertDept(name){
return new Promise(fn);
function fn(resolve,reject){
getMaxDept().then(function(rows){
var deptId = rows[0]["DeptId"];
deptId = (_.isNull(deptId) === true) ? 125 : deptId;
var sql = "insert into departmentTbl values("+deptId+",'"+name+"')";
console.log(sql);
connection.query(sql,function(err,rows,fields){
if(err){
console.log(err);
return reject(err);
}else{
return resolve(rows);
}
});
}).catch(function(error){
return reject(error);
});
}//fn
}//insertDept
function getMaxDept(){
return new Promise(fn);
function fn(resolve,reject){
var sql = "select max(deptId) + 1 as 'DeptId' from departmentTbl";
connection.query(sql,function(err,rows,fields){
if(err){
console.log(err.stack);
return reject(err);
}else{
return resolve(rows);
}
});
}// fn
} //getMaxDept
function createDeptForAll(){
var promiseObj = [];
if(arguments.length > 0){
_.each(arguments,callback);
}else{
throw "No departments passed";
}
function callback(deptName){
promiseObj.push(insertDept(deptName))
}
return Promise.all(promiseObj);
}//createDeptForAll
createDeptForAll("Archiology","Anthropology").then(function(createDepartment){
createDepartment.then(function(rows){
console.log("Rows inserted "+rows["affectedRows"]);
}).catch(function(error){
console.log(error);
}).done(function(){
connection.end();
});
});
当我运行以上代码代码时,
输出是
rahul@rahul:~/myPractise/NodeWebApp/NodeMySqlv1.0$ node queryUsingPromise02.js
insert into departmentTbl values(125,'Archiology')
insert into departmentTbl values(125,'Anthropology')
{ [Error: ER_DUP_ENTRY: Duplicate entry '125' for key 'PRIMARY'] code: 'ER_DUP_ENTRY', errno: 1062, sqlState: '23000', index: 0 }
由于 Department Id 是主键并且 promises 运行 是并行的,
第二部门的插入查询主键失败。
如您所见,在任何插入查询之前,我获取部门的最大值 + 1。
如果上述查询失败,我分配'125'。
现在,我应该更改什么以使我上面编写的代码 运行s。
我应该使用 "before insert" 的触发器在数据库级别本身计算 "department ID" 的主键的下一个值,还是应该在我自己的 Node.js 代码中做一些事情?
此问题不限于节点或 JavaScript,但您会遇到任何尝试并行写入 SQL 数据库的技术的问题。在这种情况下生成唯一 ID 并非易事。
如果您可以选择这样做,请在您的数据库中创建您的 id 字段 AUTO_INCREMENT
,这会在这种情况下为您省去很多麻烦。
AUTO_INCREMENT 上的建议看起来不错。
您也可以考虑为 connection.query()
编写一个 promisier,以便整理剩余的代码。
因此,在清除了 getMaxDept()
并安装了 connection.queryAsync()
实用程序后,您可能会得到类似这样的结果:
var Promise = require("promise");
var mySql = require("mysql");
var connection = mySql.createConnection({
host: "localhost",
user: "root",
password: "rahul",
database: "testDb" //schema
});
connection.connect();
// promisifier for connection.query()
connection.queryAsync = function(sql) {
return new Promise((resolve, reject) => {
connection.query(sql, (err, rows, fields) => {
if(err) { reject(err); }
else { resolve({'rows':rows, 'fields':fields}); }
});
});
};
function insertDept(name) {
var sql = "insert into departmentTbl values(" + name + "')"; // assumed - needs checking
return connection.queryAsync(sql);
}
function createDeptForAll(departments) {
if(departments.length > 0) {
return Promise.all(departments.map(insertDept));
} else {
return Promise.reject(new Error('No departments passed'));
}
}
createDeptForAll(['Archiology', 'Anthropology']).then((results) => {
results.forEach((result) => {
console.log("Rows inserted " + result.rows.affectedRows);
connection.end();
});
}).catch((error) => {
console.log(error);
connection.end();
});
我为 运行 在 Node.js 中并行插入查询编写了代码,我也在使用 Promise.js。
但是代码失败并引发了 "Duplicate Primary Key" 条目的异常。
代码如下,
var Promise = require("promise");
var mySql = require("mysql");
var _ = require("underscore");
var connection = mySql.createConnection({
host : "localhost",
user : "root",
password : "rahul",
database : "testDb" //schema
});
connection.connect();
function insertDept(name){
return new Promise(fn);
function fn(resolve,reject){
getMaxDept().then(function(rows){
var deptId = rows[0]["DeptId"];
deptId = (_.isNull(deptId) === true) ? 125 : deptId;
var sql = "insert into departmentTbl values("+deptId+",'"+name+"')";
console.log(sql);
connection.query(sql,function(err,rows,fields){
if(err){
console.log(err);
return reject(err);
}else{
return resolve(rows);
}
});
}).catch(function(error){
return reject(error);
});
}//fn
}//insertDept
function getMaxDept(){
return new Promise(fn);
function fn(resolve,reject){
var sql = "select max(deptId) + 1 as 'DeptId' from departmentTbl";
connection.query(sql,function(err,rows,fields){
if(err){
console.log(err.stack);
return reject(err);
}else{
return resolve(rows);
}
});
}// fn
} //getMaxDept
function createDeptForAll(){
var promiseObj = [];
if(arguments.length > 0){
_.each(arguments,callback);
}else{
throw "No departments passed";
}
function callback(deptName){
promiseObj.push(insertDept(deptName))
}
return Promise.all(promiseObj);
}//createDeptForAll
createDeptForAll("Archiology","Anthropology").then(function(createDepartment){
createDepartment.then(function(rows){
console.log("Rows inserted "+rows["affectedRows"]);
}).catch(function(error){
console.log(error);
}).done(function(){
connection.end();
});
});
当我运行以上代码代码时, 输出是
rahul@rahul:~/myPractise/NodeWebApp/NodeMySqlv1.0$ node queryUsingPromise02.js
insert into departmentTbl values(125,'Archiology')
insert into departmentTbl values(125,'Anthropology')
{ [Error: ER_DUP_ENTRY: Duplicate entry '125' for key 'PRIMARY'] code: 'ER_DUP_ENTRY', errno: 1062, sqlState: '23000', index: 0 }
由于 Department Id 是主键并且 promises 运行 是并行的, 第二部门的插入查询主键失败。
如您所见,在任何插入查询之前,我获取部门的最大值 + 1。
如果上述查询失败,我分配'125'。
现在,我应该更改什么以使我上面编写的代码 运行s。
我应该使用 "before insert" 的触发器在数据库级别本身计算 "department ID" 的主键的下一个值,还是应该在我自己的 Node.js 代码中做一些事情?
此问题不限于节点或 JavaScript,但您会遇到任何尝试并行写入 SQL 数据库的技术的问题。在这种情况下生成唯一 ID 并非易事。
如果您可以选择这样做,请在您的数据库中创建您的 id 字段 AUTO_INCREMENT
,这会在这种情况下为您省去很多麻烦。
AUTO_INCREMENT 上的建议看起来不错。
您也可以考虑为 connection.query()
编写一个 promisier,以便整理剩余的代码。
因此,在清除了 getMaxDept()
并安装了 connection.queryAsync()
实用程序后,您可能会得到类似这样的结果:
var Promise = require("promise");
var mySql = require("mysql");
var connection = mySql.createConnection({
host: "localhost",
user: "root",
password: "rahul",
database: "testDb" //schema
});
connection.connect();
// promisifier for connection.query()
connection.queryAsync = function(sql) {
return new Promise((resolve, reject) => {
connection.query(sql, (err, rows, fields) => {
if(err) { reject(err); }
else { resolve({'rows':rows, 'fields':fields}); }
});
});
};
function insertDept(name) {
var sql = "insert into departmentTbl values(" + name + "')"; // assumed - needs checking
return connection.queryAsync(sql);
}
function createDeptForAll(departments) {
if(departments.length > 0) {
return Promise.all(departments.map(insertDept));
} else {
return Promise.reject(new Error('No departments passed'));
}
}
createDeptForAll(['Archiology', 'Anthropology']).then((results) => {
results.forEach((result) => {
console.log("Rows inserted " + result.rows.affectedRows);
connection.end();
});
}).catch((error) => {
console.log(error);
connection.end();
});