MySQL JDBC驱动中的cachePrepStmts和useServerPrepStmts有什么区别
What's the difference between cachePrepStmts and useServerPrepStmts in MySQL JDBC Driver
MySQL JDBC 驱动程序将这两个属性定义为:
useServerPrepStmts - Use server-side prepared statements if the server supports them?
cachePrepStmts - Should the driver cache the parsing stage of PreparedStatements of client-side prepared statements, the "check" for
suitability of server-side prepared and server-side prepared
statements themselves?
客户端准备语句是重用 PreparedStatements
对象的一种方式吗?
如果启用了 useServerPrepStmts
,究竟缓存了什么,因为 MySQL 没有 execution plan cache anyway?
首先,区分客户端准备语句和服务器准备语句很重要。
客户准备的报表
客户端准备语句是 "emulated" 准备语句。这意味着 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
"query"表示,在协议层面,COM_QUERY
命令发送后跟语句字符串。
服务器准备好的语句
服务器准备语句是 "true" 准备语句,这意味着查询文本被发送到服务器、解析、占位符和结果信息 returned 到客户端。这是设置 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 ?")
,它将 return 在使用相同语句的连续调用中使用相同的 PreparedStatement
实例细绳。这有助于避免在事务之间return将连接returned 到池时在服务器上重复准备相同的字符串。
MySQL JDBC 选项 cachePrepStmts
将以这种方式缓存准备好的语句(客户端和服务器准备的语句)以及缓存语句的 "preparability" . MySQL中有一些语句在服务器端是不可准备的。如果驱动程序认为可能的话,它会尝试在服务器上准备一条语句,如果准备失败,则回退到客户端准备好的语句。由于需要往返服务器,此检查的成本很高。该选项还将缓存此检查的结果。
希望对您有所帮助。
MySQL JDBC 驱动程序将这两个属性定义为:
useServerPrepStmts - Use server-side prepared statements if the server supports them?
cachePrepStmts - Should the driver cache the parsing stage of PreparedStatements of client-side prepared statements, the "check" for suitability of server-side prepared and server-side prepared statements themselves?
客户端准备语句是重用 PreparedStatements
对象的一种方式吗?
如果启用了 useServerPrepStmts
,究竟缓存了什么,因为 MySQL 没有 execution plan cache anyway?
首先,区分客户端准备语句和服务器准备语句很重要。
客户准备的报表
客户端准备语句是 "emulated" 准备语句。这意味着 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
"query"表示,在协议层面,COM_QUERY
命令发送后跟语句字符串。
服务器准备好的语句
服务器准备语句是 "true" 准备语句,这意味着查询文本被发送到服务器、解析、占位符和结果信息 returned 到客户端。这是设置 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 ?")
,它将 return 在使用相同语句的连续调用中使用相同的 PreparedStatement
实例细绳。这有助于避免在事务之间return将连接returned 到池时在服务器上重复准备相同的字符串。
MySQL JDBC 选项 cachePrepStmts
将以这种方式缓存准备好的语句(客户端和服务器准备的语句)以及缓存语句的 "preparability" . MySQL中有一些语句在服务器端是不可准备的。如果驱动程序认为可能的话,它会尝试在服务器上准备一条语句,如果准备失败,则回退到客户端准备好的语句。由于需要往返服务器,此检查的成本很高。该选项还将缓存此检查的结果。
希望对您有所帮助。