如何使用MySQL准备语句缓存?

发布于 2024-07-06 21:12:10 字数 813 浏览 8 评论 0原文

我如何利用 MySQL 缓存准备好的语句的能力? 使用准备好的语句的原因之一是,如果要再次使用相同的准备好的语句,则无需多次发送准备好的语句本身。

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb" +
        "?cachePrepStmts=true", "user", "pass");
for (int i = 0; i < 5; i++) {
    PreparedStatement ps = conn.prepareStatement("select * from MYTABLE where id=?");
    ps.setInt(1, 1);
    ps.execute();
}
conn.close()

运行上面的 Java 示例时,我在 mysqld 日志文件中看到 5 对“准备”和“执行”命令。 当然,将 ps 分配移到循环之外会产生单个“准备”和 5 个“执行”命令。 连接参数“cachePrepStmts=true”在这里似乎没有任何区别。
当使用 Spring 和 Hibernate 运行类似的程序时,发送的Prepare命令的数量(1或5)取决于是否启用cachePrepStmts连接参数。 Hibernate 如何执行准备好的语句以利用cachePrepStmts 设置? 是否可以使用纯 JDBC 来模拟这个?
我在 MySQL Server 4.1.22 和 mysql-connector-java-5.0.4.jar 上运行它

How do i take advantage of MySQL's ability to cache prepared statements?
One reason to use prepared statements is that there is no need to send the prepared statement itself multiple times if the same prepared statement is to be used again.

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb" +
        "?cachePrepStmts=true", "user", "pass");
for (int i = 0; i < 5; i++) {
    PreparedStatement ps = conn.prepareStatement("select * from MYTABLE where id=?");
    ps.setInt(1, 1);
    ps.execute();
}
conn.close()

When running the above Java example I see 5 pairs of Prepare and Execute commands in the mysqld log file. Moving the ps assignment outside of the loop results in a single Prepare and 5 Execute commands of course. The connection parameter "cachePrepStmts=true" doesn't seem to make any difference here.
When running a similar program using Spring and Hibernate the number of Prepare commands sent (1 or 5) depends on whether the cachePrepStmts connection parameter is enabled. How does Hibernate execute prepared statements to take advantage of the cachePrepStmts setting? Is it possible to mimic this using pure JDBC?
I was running this on MySQL Server 4.1.22 and mysql-connector-java-5.0.4.jar

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

裂开嘴轻声笑有多痛 2024-07-13 21:12:42

首先,您的PreparedStatement 在循环中重新创建,因此允许JDBC 驱动程序丢弃准备好的数据。 所以你要求做出丑陋的行为,所以你得到了它。

然后,MySQL 中的PreparedStatement 是独立的一章。 要拥有真正的缓存,您必须通过连接属性显式请求它。

因此,您必须将“cachePrepStmts”属性设置为“true”才能缓存准备好的语句。 默认情况下,该属性设置为 false。

@有关详细信息,请参阅您的 MySQL 版本的 MySQL 手册

First, your PreparedStatement is recreated in the loop, so the JDBC driver is allowed to discard the prepared data. So you asked for the ugly behaviour, and so you got it.

And then, PreparedStatement in MySQL are a chapter on its own. To have real caching, you have to request it explicitly via a connection property.

So you have to set the "cachePrepStmts" property to "true" to get caching on prepared statements. By default, that property is set to false.

@see the MySQL manual for your MySQL version for details

风渺 2024-07-13 21:12:39

您应该在循环外准备语句。

Connection conn = DatabaseUtil.getConnection();
PreparedStatement stmtUpdate = conn.prepareStatement("UPDATE foo SET bar=? WHERE id = ?");
for(int id=0; id<10; id++){
    stmtUpdate.setString(1, "baz");
    stmtUpdate.setInt(2, id);
    int rows = stmtUpdate.executeUpdate();
    // Clear parameters for reusing the preparedStatement
    stmtUpdate.clearParameters();
}
conn.close();

我不知道 mysql 缓存准备好的语句,但这是 JDBC 准备好的语句应该重用的方式。

You should prepare the statement outside the loop.

Connection conn = DatabaseUtil.getConnection();
PreparedStatement stmtUpdate = conn.prepareStatement("UPDATE foo SET bar=? WHERE id = ?");
for(int id=0; id<10; id++){
    stmtUpdate.setString(1, "baz");
    stmtUpdate.setInt(2, id);
    int rows = stmtUpdate.executeUpdate();
    // Clear parameters for reusing the preparedStatement
    stmtUpdate.clearParameters();
}
conn.close();

I don't know about mysql caching prepared statements, but this is the way JDBC prepared statements are supposed to be reused.

猫弦 2024-07-13 21:12:36

您还需要在连接实例上设置语句缓存大小。 我假设默认缓存大小为 0。因此不会缓存任何内容。

You also need to set the statement cache size on the connection instance. I assume the default cache size is 0. Hence nothing would be cached.

南街女流氓 2024-07-13 21:12:33

是否可以使用来模仿这个
纯 JDBC?

这实际上不是您通过将准备好的语句调用移出循环所做的事情吗?

我可能误解了 MySQL 缓存的工作方式,但是日志文件是否一定会报告缓存的工作情况? Spring 或 Hibernate 可能有自己的中间缓存,用于根据之前发送的语句检查准备好的语句。 当您使用 Spring 运行该程序时,您可能会看到这样的情况。 这意味着对您的系统进行一些跟踪,看看 mysqld 日志是否只是报告它所发送的语句,无论它如何处理它们。

Is it possible to mimic this using
pure JDBC?

Is this not in fact what you've done by moving your prepared statement call out of the loop?

I may be misunderstanding the way the MySQL cache works, but does the log file necessarily report the cache's work? It may be that Spring or Hibernate has its own intermediate cache that checks the prepared statements against those sent earlier. It might be that that you're seeing when you run the program with Spring. That would mean doing a bit of tracing with your system to see if the mysqld log is just reporting the statements it's been sent, regardless of how it deals with them.

谈情不如逗狗 2024-07-13 21:12:28

您应该只在循环之外准备一次语句,然后在循环中绑定参数。 这就是准备好的语句具有绑定参数的原因 - 这样您就可以重用准备好的语句。

Hibernate 正是这样做的,在幕后将所有 SQL 视为准备好的语句,尽管如果您使用文字而不是绑定参数,您显然可以滥用这一点。

You should prepare your statement only once, outside of the loop, and then bind the parameters in the loop. This is why prepared statements have bind parameters - so you can reuse the prepared statement.

Hibernate does exactly this, treating all SQL as a prepared statement behind the scenes, though you can obviously abuse this if you use literal rather than bind parameters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文