问题
在开发过程中,我们经常需要查看 Sequelize 生成的 SQL 语句,以便于调试。
解决
主要是添加 logQueryParameters: true
,logging: true
这两个参数
1 2 3 4 5 6 7
| var sequelize = new Sequelize('database', 'username', 'password', { dialect: 'mysql', host: 'localhost', port: 3306, logQueryParameters: true, logging: true });
|
其中 logQueryParameters
表示是否打印参数,logging
表示是否打印 SQL 语句
但实际上会出现这样的状况,会发现控制台打印的参数无法在 SQL 里面执行。
1 2
| 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');
|
会变成
1 2 3
| 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 注入攻击,并提高查询的性能。
然后我去看了源码
https://github.com/sequelize/sequelize/blob/345981f2eb4c1aa709d5b831136b8dbbb32e72b8/lib/dialects/mysql/query.js#L37
1
| const complete = this._logQuery(sql, debug, parameters);
|
https://github.com/sequelize/sequelize/blob/60d16a34562d4f7ed0fa74ede65a9c641a7e6a95/packages/core/src/dialects/abstract/query.js#L361
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| _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
方法
见
https://github.com/sidorares/node-mysql2/tree/cf1a8b7d4c3bb4ee13e4362d85419efe9fb80202/documentation/zh-cn#sql预处理的使用
1 2 3 4
| const [rows, fields] = await connection.execute( 'SELECT * FROM `table` WHERE `name` = ? AND `age` > ?', ['Morty', 14] );
|
使用 MySQL2,您还可以提前准备好SQL预处理语句。 使用准备好的SQL预处理语句,MySQL 不必每次都为相同的查询做准备,这会带来更好的性能。 如果您不知道为什么它们很重要,请查看这些讨论:
所以我只简单的修改了一下源码,添加了一个输出实际 SQL 的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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();
|