问题
在开发过程中,我们经常需要查看 Sequelize 生成的 SQL 语句,以便于调试。
解决
主要是添加 logQueryParameters: true
,logging: true
这两个参数
var sequelize = new Sequelize('database', 'username', 'password', {
dialect: 'mysql',
host: 'localhost',
port: 3306,
logQueryParameters: true,
logging: true
});
其中 logQueryParameters
表示是否打印参数,logging
表示是否打印 SQL 语句
但实际上会出现这样的状况,会发现控制台打印的参数无法在 SQL 里面执行。
UPDATE `users` SET `age`=10;
INSERT INTO `UserData` (`id`,`name`,`phone`,`provinceCode`,`cityCode`,`createdAt`,`updatedAt`) VALUES (DEFAULT, '张三', '12345678901', '11', '1101', '2023-08-04 05:21:59', '2023-08-04 05:21:59');
会变成
UPDATE `users` SET `age`=?; 10
INSERT INTO `UserData`
(`id`,`name`,`phone`,`provinceCode`,`cityCode`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?,?,?); "张三", "12345678901", "11", "1101", "2023-08-04 05:21:59", "2023-08-04 05:21:59"
对于使用 Sequelize 进行插入操作,日志输出会显示带有占位符的 SQL 查询语句,这是因为 Sequelize 会使用参数化查询来防止 SQL 注入攻击,并提高查询的性能。
然后我去看了源码
const complete = this._logQuery(sql, debug, parameters);
_logQuery(sql, debugContext, parameters) {
const { connection, options } = this;
const benchmark = this.sequelize.options.benchmark || options.benchmark;
const logQueryParameters = this.sequelize.options.logQueryParameters || options.logQueryParameters;
const startTime = Date.now();
let logParameter = '';
if (logQueryParameters && parameters) {
const delimiter = sql.endsWith(';') ? '' : ';';
logParameter = `${delimiter} with parameters ${NodeUtil.inspect(parameters)}`;
}
const fmt = `(${connection.uuid || 'default'}): ${sql}${logParameter}`;
const queryLabel = options.queryLabel ? `${options.queryLabel}\n` : '';
const msg = `${queryLabel}Executing ${fmt}`;
debugContext(msg);
if (!benchmark) {
this.sequelize.log(`${queryLabel}Executing ${fmt}`, options);
}
return () => {
const afterMsg = `${queryLabel}Executed ${fmt}`;
debugContext(afterMsg);
if (benchmark) {
this.sequelize.log(afterMsg, Date.now() - startTime, options);
}
};
}
发现它并没有直接把参数替换掉,而是传入到了数组中,最后调用了 mysql2 的 execute
方法
见
const [rows, fields] = await connection.execute(
'SELECT * FROM `table` WHERE `name` = ? AND `age` > ?',
['Morty', 14]
);
使用 MySQL2,您还可以提前准备好 SQL 预处理语句。使用准备好的 SQL 预处理语句,MySQL 不必每次都为相同的查询做准备,这会带来更好的性能。如果您不知道为什么它们很重要,请查看这些讨论:
所以我只简单的修改了一下源码,添加了一个输出实际 SQL 的方法
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'your_mysql_host',
user: 'your_mysql_username',
password: 'your_mysql_password',
database: 'your_mysql_database',
});
const sql = 'SELECT * FROM your_table WHERE column = ?';
const values = ['some_value'];
connection.execute(sql, values, (err, results) => {
if (err) {
console.error('Error executing query:', err.message);
return;
}
console.log('Query:', connection.format(sql, values)); // 打印查询语句
console.log('Results:', results);
});
connection.end();