关闭PreparedStatement是否也会释放其在数据库连接中的内存占用?

问题描述 投票:0回答:2

据我了解,每次初始化

PreparedStatement
时,该语句都会缓存在为数据库连接分配的内存中。因此,如果初始化过多的
PreparedStatement
变量,则存在连接可用内存溢出的风险。

  1. 是否通过在

    close()
    实例上调用
    PreparedStatement
    释放缓存内存?

  2. 执行两个包含相同 SQL 的

    PreparedStatement
    创建重复的缓存事件,或者数据库是否足够智能,不会缓存重复
    PreparedStatement
    的新实例?

示例1,这样会导致连接内存溢出吗?:

while (true) {
    PreparedStatement ps = connection.prepareStatement("SELECT id + ? FROM tbl");
    ps.setDouble(1, Math.random());
    ps.executeQuery();
    ps.close();
}

如果可以的话,那这个呢?:

while (true) {
    PreparedStatement ps = connection.prepareStatement("SELECT id FROM tbl");
    ps.executeQuery();
    ps.close();
}
java mysql sql postgresql jdbc
2个回答
0
投票

两者的答案:这完全取决于 JDBC 驱动程序。

例如对于 PostgreSQL JDBC 驱动程序,请参阅服务器准备语句

当使用 PreparedStatement API 时,驱动程序默认使用服务器端准备好的语句。为了进入服务器端准备,您需要执行查询 5 次(可以通过

prepareThreshold
连接属性进行配置)。内部计数器跟踪语句已执行的次数,当达到阈值时,它将开始使用服务器端准备好的语句。
出于性能原因,重用相同的 

PreparedStatement

对象通常是一个好主意,但是驱动程序能够跨

connection.prepareStatement(...)
调用自动服务器准备语句。
[...]

服务器准备的语句会消耗客户端和服务器上的内存,因此 pgjdbc 限制每个连接的服务器准备的语句数量。它可以通过

preparedStatementCacheQueries

(默认

256
,pgjdbc 已知的查询数量)和
preparedStatementCacheSizeMiB
(默认
5
,即每个连接的客户端缓存大小(以 MB 为单位)进行配置)。只有
statement cache
的子集是服务器准备的,因为某些语句可能无法到达
prepareThreshold

对于 MS SQL Server JDBC 驱动程序,请参阅
JDBC 驱动程序的准备语句元数据缓存

对于 MySQL JDBC 驱动程序,请参阅

Prepared Statement Cache with MySQL & JDBC

的答案。 我没有看到 Oracle JDBC 驱动程序有任何此类功能。


0
投票
并非所有驱动程序都支持预编译。
  1. JDBC 和数据库都会在必要时执行缓存驱逐。
  2. Oracle JDBC 驱动程序示例:

来源:

https://docs.oracle.com/cd/B28359_01/java.111/b31224/stmtcach.htm

从缓存中删除语句以符合最大大小 使用最近最少使用 (LRU) 算法。

© www.soinside.com 2019 - 2024. All rights reserved.