首页 > 解决方案 > Java、JDBC:关闭 PreparedStatement 是否也会释放其在数据库连接中的内存占用?

问题描述

据我了解,每次PreparedStatement初始化 a 时,该语句都会缓存在为数据库连接分配的内存中。因此,如果初始化过多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();
}

标签: javamysqlsqlpostgresqljdbc

解决方案


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

例如,对于 PostgreSQL JDBC 驱动程序,请参阅Server Prepared Statements

使用API时,驱动程序默认使用服务器端准备好的语句。PreparedStatement为了进行服务器端准备,您需要执行 5 次查询(可以通过prepareThreshold连接属性进行配置)。内部计数器跟踪语句执行了多少次,当它达到阈值时,它将开始使用服务器端准备好的语句。

出于性能原因,重用同一个对象通常是一个好主意,但是驱动程序能够跨调用PreparedStatement自动准备服务器语句。connection.prepareStatement(...)

[...]

服务器准备的语句在客户端和服务器上都消耗内存,因此 pgjdbc 限制每个连接的服务器准备语句的数量。它可以通过preparedStatementCacheQueries(默认256,pgjdbc 已知的查询数)和preparedStatementCacheSizeMiB(默认5,即客户端缓存大小,以每个连接的兆字节为单位)进行配置。只有一个子集statement cache是服务器准备的,因为某些语句可能无法到达prepareThreshold.

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

对于 MySQL JDBC 驱动程序,请参阅Prepared Statement Cache with MySQL & JDBC 的回答。

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


推荐阅读