我使用MySQL Connector/J (版本8.0.28)作为客户端的驱动程序。以下是我用于测试的代码的一部分:
PreparedStatement ps = null;
String url = "jdbc:mysql://10.86.49.16:3306/test?useServerPrepStmts=true&cachePrepStmts=true";
...
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, password);
String sql = "select * from test where id=?";
for (int i = 1; i <= 3; i++) {
ps = conn.prepareStatement(sql);
ps.setInt(1, i);
ps.execute();
ps.close();
}
单独设置"useServerPrepStmts=true“时,我的一般日志如下所示:
6 Prepare select * from test where id=?
6 Execute select * from test where id=1
6 Close stmt
6 Prepare select * from test where id=?
6 Execute select * from test where id=2
6 Close stmt
6 Prepare select * from test where id=?
6 Execute select * from test where id=3
6 Close stmt
但是,在一起启用"cachePrepStmts“()之后,日志变成:
7 Prepare select * from test where id=?
7 Execute select * from test where id=1
7 Reset stmt
7 Execute select * from test where id=2
7 Reset stmt
7 Execute select * from test where id=3
看来准备好的语句缓存确实生效了,但是有意外的“重置stmt”,这会导致额外的往返。我检查了MySQL连接器/J的源代码,并在关闭准备好的语句时发现了执行的奇怪逻辑。它将总是将longParameterSwitchDetected设置为真正的,在我的例子中是!
com.mysql.cj.ServerPreparedQuery#clearParameters
/**
* @param clearServerParameters
* flag indicating whether we need an additional clean up
*/
public void clearParameters(boolean clearServerParameters) {
boolean hadLongData = false;
if (this.queryBindings != null) {
hadLongData = this.queryBindings.clearBindValues();
this.queryBindings.setLongParameterSwitchDetected(clearServerParameters && hadLongData ? false : true);
}
...
}
然后,当下一个"Execute“出现时,它将检查此标志并决定是否发送"Reset stmt”,如下所示:
com.mysql.cj.ServerPreparedQuery#prepareExecutePacket
public NativePacketPayload prepareExecutePacket() {
ServerPreparedQueryBindValue[] parameterBindings = this.que
if (this.queryBindings.isLongParameterSwitchDetected()) {
...
// Okay, we've got all "newly"-bound streams, so reset server-side state to clear out previous bindings
serverResetStatement();
}
...
}
我尝试在调试模式下手动将此longParameterSwitchDetected设置为false,并在没有发送“重置stmt”的情况下成功执行该语句。以下是我的问题:
是否有任何用于删除此“重置stmt"?
的确切含义/逻辑
发布于 2022-04-24 10:19:40
这实际上是MySQL连接器/J中的一个代码错误,在与作者接触之后。我已经向社区报告过了。请参阅https://bugs.mysql.com/bug.php?id=107107
https://stackoverflow.com/questions/71967394
复制相似问题