我有一个 java 库来查询 mysql 数据库
,将 ResultSet
返回给另一个 Java 函数。由于mysql超时问题,我使用c3p0 pool
来实现查询。
cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl(url);
cpds.setUser(user);
cpds.setPassword(passwd);
cpds.setMaxPoolSize(maxPoolSize);
cpds.setMinPoolSize(minPoolSize);
cpds.setAcquireIncrement(20);
public ResultSet fetch() {
PreparedStatement pst = null;
ResultSet rs = null;
String query = null;
Connection conn = null;
try {
conn = cpds.getConnection();
query = "...";
pst = conn.prepareStatement(query);
rs = pst.executeQuery();
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}finally {
try {
if(conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
return rs;
}
}
我遇到了这个错误
SEVERE: Operation not allowed after ResultSet closed java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1075)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:929)
at com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:795)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:7146)
at com.mchange.v2.c3p0.impl.NewProxyResultSet.next(NewProxyResultSet.java:622)
原因很明显,但我在想调用 Mysql 查询并在函数中获取结果的最佳方式是什么。
最佳答案
在 finally 子句中,连接在方法返回之前关闭。
}finally {
try {
if(conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
此连接是由 c3p0 管理的 PooledConnection。 close() 方法只是将 Connection 返回到池中,而不关闭它。在将连接返回到池之前清理语句,以防止资源泄漏和池损坏。
当 Statements 关闭时,它的当前 ResultSet 对象(如果存在)也将关闭。检查 java 7 API 语句 close() 方法 here
因此,当 fetch() 返回时,ResultSet 被关闭。
建议:
这是 java JDBC 编程中的一个常见问题。
第一个选项,将 fetch() 更改为模板方法的代码
public ResultSet fetch(ResultSetIterator rsIterator ) {
PreparedStatement pst = null;
ResultSet rs = null;
String query = null;
Connection conn = null;
try {
conn = cpds.getConnection();
query = "select * from tb_user";
pst = conn.prepareStatement(query);
rs = pst.executeQuery();
rsIterator.iterate(rs);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}finally {
try {
if(conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
return rs;
}
ResultSetIterator 有处理 ResultSet 的代码
第二个选项,使用已经实现的工具,比如Commons DbUtils , 点击链接查看示例
其他选项,使用 ER 映射工具、JPA、hibernate 等...抽象连接句柄
最后,为了解决超时问题和测试连接池,使用DBCP代替 c3p0,一个更健壮的解决方案
private static DataSource setupDataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(getDriver());
ds.setUsername(getUser());
ds.setPassword(getPassword());
ds.setUrl(getConnectionString());
ds.setDefaultAutoCommit(false);
ds.setInitialSize(4);
ds.setMaxActive(60);
ds.setMaxIdle(10);
ds.setValidationQuery("/* ping */ SELECT 1");//config to validate against mysql
ds.setValidationQueryTimeout(3);
ds.setTestOnBorrow(true);
ds.setTestOnReturn(true);
return ds;
}
关于java调用mysql c3p0函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11306068/