在MySQL上使用Promise进行并行插入查询失败

我写了一个在Node.js中并行运行插入查询的代码,我也使用Promise.js。

但代码失败并引发“重复主键”条目的例外。

代码如下,

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是主键,并且承诺并行运行,所以第二个部门的插入查询的主键失败。

正如你所看到的,在任何插入查询之前,我获取最多的部门+ 1。

如果上面的查询失败,我分配'125'。

现在,我应该改变什么,以便我的上面的代码运行。

我应该使用“插入之前”的触发器来计算数据库级别本身的“部门ID”主键的下一个值,还是我应该在自己的Node.js代码中做一些事情?

此问题不限于节点或JavaScript,但是您将面临任何试图并行写入SQL数据库的技术的问题。 在这种情况下生成唯一的身份证并不是微不足道的。

如果你有select的话,可以在数据库AUTO_INCREMENT你的id字段,这样可以节省你很多麻烦。

更多关于AUTO_INCREMENT

对AUTO_INCREMENT的build议看起来不错。

你也可以考虑为connection.query()写一个promisifier,允许整理其余的代码。

所以,清除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(); });