2015-08-29 33 views
14

MySQL JDBC驱动程序这两个属性定义为cachePrepStmts和useServerPrepStmts之间的区别:是什么在MySQL JDBC驱动程序

  • useServerPrepStmts - 如果服务器支持,他们使用服务器端预处理语句?

  • cachePrepStmts - 如果司机缓存客户端的预处理语句的分析阶段编制报表时,“检查​​”的 适合服务器端的准备和服务器端的准备 语句本身?

是客户端预处理语句重用PreparedStatements对象的方法吗?

如果启用了useServerPrepStmts,那么究竟是什么被缓存了,因为MySQL没有execution plan cache anyway

回答

34

首先,区分客户端和服务器准备的语句很重要。

客户端准备语句

客户端准备语句是“模拟”准备语句。这意味着SQL语句字符串在客户端被标记化,并且在将语句发送到服务器执行前,任何占位符都被替换为文字值。每次执行时都会向服务器发送完整的SQL语句。您可以使用通用日志来调查这是如何工作的。例如

下面的代码:

ps=conn.prepareStatement("select ?") 
ps.setInt(1, 42) 
ps.executeQuery() 
ps.setInt(1, 43) 
ps.executeQuery() 

会显示在日志中:

255 Query select 42 
255 Query select 43 

“查询”表示,在协议层面,一个COM_QUERY命令与语句字符串发送以下。

服务器预处理语句

服务器预处理语句是“真”准备的语句意味着查询将文本发送到服务器,解析和占位和结果信息返回给客户端。这是您在设置useServerPrepStmts=true时所得到的结果。语句字符串一次只能通过COM_STMT_PREPARE调用(文档here)发送到服务器。通过发送COM_STMT_EXECUTE来执行每个执行,其中包含准备好的语句句柄和文字值以替代占位符。

与客户端编写例子对比,我们可以用相似的代码块(但这次服务器预处理语句启用):

ps2=conn2.prepareStatement("select ?") 
ps2.setInt(1, 42) 
ps2.executeQuery() 
ps2.setInt(1, 43) 
ps2.executeQuery() 

和日志会显示:

254 Prepare select ? 
254 Execute select 42 
254 Execute select 43 

您可以看到该语句在执行前已经准备好。日志为我们提供了一个帮助,并显示了完整的执行语句,但事实上,每次执行时,只有占位符值从客户端发送到服务器。

缓存预处理语句

许多连接池将缓存跨越这意味着,如果你调用conn.prepareStatement("select ?"),它将返回与相同的语句串连续调用同一个PreparedStatement实例的连接使用准备好的语句。这有助于避免连接在事务之间返回到池时在服务器上重复准备相同的字符串。

MySQL JDBC选项cachePrepStmts将以这种方式(客户端和服务器准备语句)缓存预准备语句,并缓存语句的“可预备性”。 MySQL中有一些不可在服务器端准备的语句。驱动程序会尝试在服务器上准备一份声明,如果它认为可能,并且如果准备失败,则会回到客户准备好的声明。由于需要往返于服务器,所以此检查很昂贵。该选项还会缓存此检查的结果。

希望这会有所帮助。

+1

非常好的解释。我不知道在发送到服务器之前,客户端语句绑定值在客户端被替换。 –

+0

似乎useServerPrepStmts属性在默认情况下是禁用的,即设置为false,这基本上意味着大多数应用程序默认默认为客户端PS?另外,它提供了什么意义/好处,因为cachePrepStmts默认也是禁用的? – sactiw