java - c3p0 Prepared Statement 无明显原因关闭

标签 java jdbc c3p0

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

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

我有一个对象,它在初始化时准备了几个准备好的语句。为此,我从 PooledDataSource 获取一个连接 (con = getConnection()),然后准备一条语句(例如,PreparedStatement stmt = con.preparedStatemet(/*sql*/))。准备好的语句作为私有(private)变量存储在对象中,当前连接在初始化结束时关闭 (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的语句缓存有什么用。

最佳答案

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

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

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

希望对您有所帮助!

关于java - c3p0 Prepared Statement 无明显原因关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17448679/

相关文章:

java - createStatement()方法如何返回Statement对象?

java - 准备好的语句生命周期和 c3p0

java - 在 arraylist 中查找并打印重复值的最有效方法是什么?

Java:如何从 Oracle DB 表解析 XML 类型列数据?

Java jdbc 批量仅插入新行

java - 跨多个 <Host> 元素为公共(public)库共享单个类加载器是否安全?

spring - hibernate模块的类加载器看不到hibernate-c3p0

java - 按匈牙利语字母顺序对匈牙利语字符串列表进行排序

java - JSP 中的 ReCaptcha

java - MyBatis - jdbcTypeForNull 甲骨文