MySQL JDBC Driver中cachePrepStmts和useServerPrepStmts之间的区别是什么

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中有一些语句在服务器端无法编写.如果驱动程序认为可能,则驱动程序将尝试在服务器上准备语句,如果准备失败,则返回到客户端准备语句.由于需要往返服务器,因此检查很昂贵.该选项还将缓存此检查的结果.

希望这可以帮助.

  • 似乎 useServerPrepStmts 属性默认被禁用,即设置为 false,这基本上意味着大多数应用程序默默地默认为客户端 PS?另外,鉴于默认情况下也禁用了cachePrepStmts,它提供了什么意义/好处? (3认同)
  • 非常好的解释.在发送到服务器之前,我不知道客户端语句绑定值在客户端被替换. (2认同)