c3p0 Prepared Statement 无故关闭

Posted

技术标签:

【中文标题】c3p0 Prepared Statement 无故关闭【英文标题】:c3p0 Prepared Statement closed for no apparent reason 【发布时间】:2013-07-03 12:57:53 【问题描述】:

我正在使用 c3p0。我设置了一个池如下,

cpds = new ComboPooledDataSource();
cpds.setJdbcUrl(...);
/* connection setup */
spds.setMaxStatements(200);

我有一个对象,它在初始化时准备了几个准备好的语句。为此,我从 PooledDataSource 中获取一个连接(con = getConnection()),然后准备一个语句(例如,PreparedStatement stmt = con.preparedStatemet(/*sql*/))。准备好的语句作为私有变量存储在对象中,当前连接在初始化结束时关闭 (con.close())。准备好的语句用于对象的方法中。

对于更新数据库的准备好的语句,这工作得很好。但是,当我调用使用准备好的语句 (stmt.executeQuery()) 来查询数据库的方法时,我得到以下 SQLException

java.sql.SQLException: You can't operate on a closed Statement!!!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:127)

我在 c3p0 的使用方面有什么问题吗?

非常感谢!

编辑:显然,我的问题部分是基于我缺乏理解。正如在明确答案中指出的那样,PreparedStatement 属于一个连接,并且每当连接关闭时,相关的语句也应该关闭。但是如果是这样的话,我不明白c3p0的语句缓存有什么用。

【问题讨论】:

我猜想连接会关闭它知道的语句。但是,我正在努力在某个地方找到与此一致的明确参考。 【参考方案1】:

调用executeUpdate() 时应该得到相同的异常。 JDBC 连接和语句池的设计是透明的:适用于非池化数据源的 API 也应该用于池化版本。性能会有很大差异,但代码在语义上应该是可互换的。

在非池化环境中,您的方法失败的原因应该很明显:语句,无论是否准备好,都是 Connection 的子级,没有它就无法运行。您希望在池化环境中,即使连接已“关闭”,它仍应存在于池中,所以嘿,那些语句可能是好的。但这是一个非常糟糕的主意(如果在父 Connection 已关闭()之后您的更新尝试确实成功了,那么这将是一个错误,一个糟糕的错误。)一旦 Connection 已“关闭”它会回到游泳池,但不会永远。其他客户端将检查它,并开始执行不应被您的陈旧语句中断的事务工作。最终连接将在池中过期。那么你保留的 PreparedStatements 应该怎么办?

c3p0 pools 透明地声明语句,这意味着您应该使用与没有池时使用的完全相同的 API。每次都在您的 Connection 上调用 prepareStatement(...)。如果您在 c3p0 中启用了语句池(如您所见),那么 c3p0 将在内部检查语句是否已经准备好,如果是,它将悄悄地使用缓存版本而不是将请求转发到 dbms。

我希望这会有所帮助!

【讨论】:

以上是关于c3p0 Prepared Statement 无故关闭的主要内容,如果未能解决你的问题,请参考以下文章

Prepared SQL Statement Syntax

使用 Prepared Statement 设置 LONG 数据类型

当 Statement 与 Java 和 Oracle 一起使用时,Prepared Statement 不起作用

MySQL Prepared Statement:更新多个值

MYSQLI Prepared statement update statement with where in array

未找到 Java Prepared statement 错误表