我调查了很多地方,听到了很多可疑的说法,从PreparedStatement
应该优先于Statement
任何地方,即使只是为了性能优势;一直声称PreparedStatement
s 应该专门用于批处理语句而不是其他任何东西。
然而,我所关注的(主要是在线)讨论似乎存在盲点。让我介绍一个具体的场景。
我们有一个带有数据库连接池的 EDA 设计的应用程序。事件来了,有些需要坚持,有些则不需要。有些是人为生成的(例如,每 X 分钟更新/重置一次)。一些事件来并按顺序处理,但其他类型的事件(也需要持久性)可以(并且将)同时处理。
除了那些人为生成的事件之外,在需要持久性的事件如何到达方面没有任何结构。
这个应用程序是很久以前(大约 2005 年)设计的,并且支持多个 DBMS。典型的事件处理程序(需要持久性):
- 从池中获取连接
- 准备sql语句
- 执行准备好的语句
- 处理结果集,如果适用,关闭它
- 关闭准备好的语句
- 如有必要,准备不同的声明并以相同的方式处理
- 将连接返回到池
如果一个事件需要批处理,则语句准备一次并使用addBatch
/executeBatch
方法。这是一个明显的性能优势,这些情况与这个问题无关。
最近,我收到一个意见,即准备(解析)语句、执行一次并关闭的整个想法本质上是对PreparedStatement
. (Oracle、DB2、MSSQL、MySQL、Derby 等)甚至不会将这样的语句提升到预准备语句缓存(或者至少,它们的默认 JDBC 驱动程序/数据源不会)。
此外,我必须在 MySQL 的开发环境中测试某些场景,Connector/J 使用分析器似乎同意这个想法。对于所有非批量准备好的语句,调用close()
打印:
PreparedStatement created, but used 1 or fewer times. It is more efficient to prepare statements once, and re-use them many times
由于前面概述的应用程序设计选择,拥有一个PreparedStatement
实例缓存来保存连接池中每个连接的任何事件使用的每条 SQL 语句,这听起来像是一个糟糕的选择。
有人可以进一步详细说明吗?“准备 - 执行(一次) - 关闭”的逻辑是否存在缺陷并且基本上不鼓励?
PS 在为每个非批处理 SQL 语句调用实例时,为 Connector/J 显式指定and并使用其中useUsageAdvisor=true
之一cachePrepStmts=true
或useServerPrepStmts=true
仍然useServerPrepStmts=false
会导致有关效率的警告。close()
PreparedStatement