如何在批量插入中使用 mysql / Node.js 中的 sql 字符串正确转义?

How to properaly escape using mysql / sqlstring in Node.js in bulk INSERT?

我正在使用这些节点模块:

const mysql = require('mysql');
const SqlString = require('sqlstring');

我从文件中读取 JSON 并将 JSON 解析为嵌套数组。然后我将嵌套数组传递到一个批量 MySQL INSERT.

这适用于 26 个文件中的 25 个文件并加载超过 500 条记录。一个文件有 21 JSON 条记录,只有以下记录失败:

[
    {
        "abstract": "... AWS Shared responsibility model:​ https://aws.amazon.com/compliance/shared-responsibility-model/; Enabling object-level logs in S3:​ ...",
        "title": "Defeating a Cloud Breach Part 1"
    }
]

我已将问题隔离到 "abstract" 字段。

我尝试在使用 "mysql" 和 connection.escape() 和 SqlString.escape() 加载到数组之前转义 "abstract" 的值=55=] 模块,分别。这两种情况都无法纠正导致 INSERT 失败的任何原因。

无论使用何种方法,INSERT 都会返回 "undefined" 失败。成功的 INSERT returns 类似于:

OkPacket {
  fieldCount: 0,
  affectedRows: 4,
  insertId: 142,
  serverStatus: 2,
  warningCount: 0,
  message: '&Records: 4  Duplicates: 0  Warnings: 0',
  protocol41: true,
  changedRows: 0
}

MySQLtable中的"abstract"列属于"text"类型,还有许多其他记录的长度超过了上述问题记录。

SqlString——当我遍历 JSON 键/值时,我尝试在放入嵌套数组之前转义字符串。

示例:摘要 = SqlString.escape(值))

我还尝试了整个 INSERT 语句,因此:

var sql = "INSERT INTO tbl (abstract,title,url,key_word) VALUES ?";

sql = SqlString.format(sql, [dbVals]);

var query = client.query(sql, function(err, result) {
console.log(result);
});

显然在上面的 clode 中 "client" 是 "mysql" CONNECTIONS 的一个实例(这就是为什么我也尝试起诉 mysql.escape() 和 client.escape( ) 代替 SqlString.escape())

但我得到的结果完全相同 只有这一条记录

我已确认此内容是问题所在,因为我已删除上面的记录并将抽象的值设置为空字符串,并且在这两个实例中批量插入都成功。

我希望能有第二双眼睛。更好的是,我希望能得到指导,指出我在正确转义内容方面做错了什么,这样以后就不会再担心了。

谢谢。

编辑:向问题添加了更多详细信息。

我怀疑您的问题可能与架构有关。同样令人困惑:您的示例的一部分表明您正在尝试插入 4 个值 (abstract,title,url,key_word),但您的有效负载仅包含 2 个字段 - 不清楚该差异或如何在数据库端处理 defaults/nulls。

使用最佳猜测模式使用您提供的示例负载进行测试,我没有遇到任何问题。由于您的有效负载仅包含 2 个字段,因此我的测试仅包含这些字段。以下每个组件的示例可与您自己的组件进行比较。

如果您仍然遇到问题,请随时分享有关您的数据库、table 架构和字段的更多详细信息。您的数据库的 charset、table 和字段可能也是一个很好的调查细节。

数据库详细信息
MySQL v5.7.12

CREATE TABLE `tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `abstract` text,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

节点

// 
// other require items here as well depending on file location in project
// 
const mysql = require('mysql');

const db = mysql.createPool({
  connectionLimit: 10,
  host: process.env.DB_HOST || '127.0.0.1',
  user: process.env.DB_USER || 'local_user',
  password: process.env.DB_PASSWORD || 'local_password',
  database: process.env.DB_NAME || 'local_database',
  multipleStatements: true, 
  charset: 'utf8mb4' // necessary if you might need support for emoji characters
});

let entries = [
  {
    "abstract": "An easy one",
    "title": "Defeating a Cloud Breach Part 0"
  },
  {
    "abstract": "... AWS Shared responsibility model:​ https://aws.amazon.com/compliance/shared-responsibility-model/; Enabling object-level logs in S3:​ ...",
    "title": "Defeating a Cloud Breach Part 1"
  },
  {
    "abstract": "Another easy one",
    "title": "Defeating a Cloud Breach Part 2"
  }
]
let keys = Object.keys(entries[0]);
let values = entries.map( obj => keys.map( key => obj[key]));
let sql = 'INSERT INTO tbl (' + keys.join(',') + ') VALUES ?;';
db.query(sql, [values], function (error, results) {
  if (error) console.log(error.code);
  console.log(results);
});

结果

OkPacket {
  fieldCount: 0,
  affectedRows: 3,
  insertId: 1,
  serverStatus: 2,
  warningCount: 0,
  message: '&Records: 3  Duplicates: 0  Warnings: 0',
  protocol41: true,
  changedRows: 0
}