Vla*_*cea 17 mysql database caching jdbc prepared-statement
MySQL JDBC Driver将这两个属性定义为:
useServerPrepStmts - 如果服务器支持,请使用服务器端预处理语句?
cachePrepStmts - 驱动程序是否应该缓存客户端预处理语句的PreparedStatements的解析阶段,"检查"服务器端准备和服务器端预处理语句本身的适用性?
客户端准备好的语句是否可以重用PreparedStatements对象?
如果useServerPrepStmts启用了,那么究竟正在缓存什么,因为MySQL还没有执行计划缓存?
小智 48
首先,区分客户端和服务器预处理语句很重要.
客户准备的语句是"模拟"的准备语句.这意味着在将语句发送到服务器以供执行之前,SQL语句字符串在客户端标记化,并且任何占位符都替换为文字值.每次执行时都会向服务器发送一个完整的SQL语句.您可以使用常规日志来调查其工作原理.例如
以下代码:
ps=conn.prepareStatement("select ?")
ps.setInt(1, 42)
ps.executeQuery()
ps.setInt(1, 43)
ps.executeQuery()
Run Code Online (Sandbox Code Playgroud)
会在日志中显示:
255 Query select 42
255 Query select 43
Run Code Online (Sandbox Code Playgroud)
"查询"表示在协议级别COM_QUERY上发送一个命令,其中包含语句字符串.
服务器预处理语句是"真实的"预处理语句,意味着查询文本被发送到服务器,解析,占位符和结果信息返回给客户端.这是你在设置时得到的useServerPrepStmts=true.语句字符串仅通过COM_STMT_PREPARE调用一次发送到服务器(此处记录).每次执行都是通过发送COM_STMT_EXECUTE带有准备好的语句句柄和文字值来替换占位符来执行的.
与客户端准备的示例相比,我们可以使用类似的代码块(但这次启用了服务器预处理语句):
ps2=conn2.prepareStatement("select ?")
ps2.setInt(1, 42)
ps2.executeQuery()
ps2.setInt(1, 43)
ps2.executeQuery()
Run Code Online (Sandbox Code Playgroud)
日志会显示:
254 Prepare select ?
254 Execute select 42
254 Execute select 43
Run Code Online (Sandbox Code Playgroud)
您可以看到该语句在执行之前已准备好.日志正在为我们提供帮助并显示执行的完整语句,但事实上,每次执行时,只有占位符值从客户端发送到服务器.
许多连接池将跨连接的使用缓存预准备语句,这意味着如果您调用conn.prepareStatement("select ?")它,它将PreparedStatement在具有相同语句字符串的后续调用中返回相同的实例.当在事务之间将连接返回到池时,这有助于避免重复在服务器上准备相同的字符串.
MySQL JDBC选项cachePrepStmts将以这种方式(客户端和服务器预处理语句)缓存预准备语句,以及缓存语句的"可预测性".MySQL中有一些语句在服务器端无法编写.如果驱动程序认为可能,则驱动程序将尝试在服务器上准备语句,如果准备失败,则返回到客户端准备语句.由于需要往返服务器,因此检查很昂贵.该选项还将缓存此检查的结果.
希望这可以帮助.