感谢您抽出时间。我在使用mysql2/promise包创建事务查询时遇到了问题。
以下是查询:
await db.execute(`START TRANSACTION`);
await db.execute(`INSERT INTO user VALUES (?, ?, ?, ?, ?, ?)`, [...userDetails]);
await db.execute(`INSERT INTO account VALUES (?, ?, ?, ?, ?, ?)`, [...accountDetails]);
await db.execute(`COMMIT`);
我得到的错误是:
Error: This command is not supported in the prepared statement protocol yet
code: 'ER_UNSUPPORTED_PS',
errno: 1295,
sql: 'START TRANSACTION',
sqlState: 'HY000',
sqlMessage: 'This command is not supported in the prepared statement protocol yet'
我想知道是否与我的查询有关?我认为INSERT语句在事务块中应该非常好。我还尝试将每个查询组合成一个字符串,但这似乎也不起作用。
MySQL限制了哪些语句可以在准备好的语句中完成,不允许使用start transaction
。请参阅Prepared Statements中允许的SQL语法,这里有一个演示。
execute
总是使用和缓存准备好的语句。如果查询很复杂(MySQL不必每次都解析它(或需要参数(为了安全起见(,这是很好的。
但是,如果您的查询很简单,并且不接受任何参数,则无需准备它。请使用仅运行SQL的query
。这既避免了出现错误,又避免了填满准备好的语句缓存。
await db.query(`START TRANSACTION`);
await db.execute(`INSERT INTO user VALUES (?, ?, ?, ?, ?, ?)`, [...userDetails]);
await db.execute(`INSERT INTO account VALUES (?, ?, ?, ?, ?, ?)`, [...accountDetails]);
await db.query(`COMMIT`);
我认为这个问题的答案是正确的,但代码(示例(不是,也不应该使用。尽管这些语句可能有效,但它不会创建有效的事务,因为可能已经建立了与数据库的新连接。
正确的方法是获得一个连接句柄:
let conn = await this.getConnection();
await conn.query('START TRANSACTION');
// do your stuff here
await conn.execute('...')'
await conn.query('COMMIT');
conn.release();
这确保了一个有效的事务(START和COMMIT应该在同一个连接上(。除非只指定了一个连接,否则直接调用数据库对象并不能提供这种保证。