2008-10-21 73 views
8

如何利用MySQL缓存预准备语句的能力? 使用预处理语句的一个原因是,如果再次使用相同的预处理语句,则不需要多次发送预处理语句本身。如何使用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对Prepare和Execute命令。将ps赋值移到循环外面当然会产生一个Prepare和5 Execute命令。连接参数“cachePrepStmts = true”在这里似乎没有任何区别。
当使用Spring和Hibernate运行类似的程序时,发送的Prepare命令的数量(1或5)取决于是否启用了cachePrepStmts连接参数。 Hibernate如何执行预处理语句以利用cachePrepStmts设置?有没有可能使用纯JDBC来模仿这个?
我MySQL服务器4.1.22和MySQL连接器的Java-5.0.4.jar

回答

2

上运行这是否有可能模仿这种用纯 JDBC?

这实际上不是你通过将准备好的语句调用移出循环而完成的吗?

我可能会误解MySQL缓存的工作方式,但日志文件是否必须报告缓存的工作? Spring或Hibernate可能有自己的中间缓存,用于检查预先准备好的语句与之前发送的语句。这可能是你在用Spring运行程序时看到的。这意味着要对系统进行一些跟踪,以查看mysqld日志是否只是报告已发送的语句,而不管它如何处理它们。

2

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

Hibernate确实做到了这一点,将所有SQL视为幕后准备好的语句,尽管如果使用文本而不是绑定参数,显然可能会滥用这一点。

1

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

然后,MySQL中的PreparedStatement是它自己的一章。要有真正的缓存,你必须通过连接属性明确地请求它。

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

@请参阅MySQL版本的MySQL手册了解详细信息

1

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

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准备语句应该重用的方式。

2

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