java call mysql c3p0 function - java

I have a java library to query mysql database, the return the ResultSet to another Java function. Because of the mysql timeout issue, I used c3p0 pool to implement the query.
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;
}
}
I got this error
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)
The reason it obvirous, but I am thinking what is the best way to call Mysql query and get results in a function.

In the finally clause, the connection is closed before the method returns.
}finally {
try {
if(conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Query.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
This Connection is a PooledConnection managed by c3p0. The close() method just return the Connection to pool, without close it. Statements are cleaned-up before the Connection is returned to pool to prevent resource leaks and pool corruption.
When Statements are closed, its current ResultSet object, if one exists, is also closed. Check the java 7 API Statement close() method here
So, the ResultSet is closed when fetch() returns.
Sugestions:
It´s a common addressed problem in java JDBC programming.
First option, code to change fetch() to operate as a template method
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 has the code to process the ResultSet
Second option, use a tool already implemented, like Commons DbUtils, follow the link to see the samples
Other option, use a ER Mapping tool, JPA, hibernate, etc... that abstract the connection handle
Finally, to address the timeout problem and test of connection pooled, use DBCP instead of c3p0, a more robust solution
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;
}

Error stack says that
SEVERE: Operation not allowed after ResultSet closed java.sql.SQLException:
Operation not allowed after ResultSet closed
This error is thrown because, you tried to use the returned instance of ResultSet object,
which is actually released during a database connection close request. And hence you can't use returned ResultSet instance any more constructively.
Documentation says that con.close() "Releases this Connection object's database and JDBC resources immediately instead of waiting for them to be automatically released.". Here JDBC resources means all the Statement objects, ResultSet objects, etc that are created using the connection object that is being closed.
Suggested Solution:
You should define a ResultDataObject class or something meaningful and fill a list of its instances while looping the resultset object in the fetch() method. Sample code snippet is shown below.
public List<ResultDataObject> fetch() {
List<ResultDataObject> list = null; // new ArrayList<ResultDataObject>( 24 );
// ...
rs = pst.executeQuery();
// now prepare the list with results filled and return
if ( list == null ) list = new ArrayList<ResultDataObject>( 24 );
// now read from result set
while ( rs.next() ) {
ResultDataObject resultData = new ResultDataObject(); // or something relevant
// use the following type methods to read from rs and fill result object
resultData.setXXX( rs.getXXX( ... ) );
// ...
list.add( resultData );
} // while rs
// do something if required before return
// ...
return list;
} // fetch()

Thank you everyone for suggestion. I have some ideas and concerns:
1) Run ResultSet rs.close() in the upper level function. But I am not sure whether the connection resource is released or not. It is very important to release the connection resource.
2) create another Object List to temparary save ResultSet structure, and return it to upper level function. My concern is the cost, since I need to create/free the temparary resource twice. It is a problem for large query.
3) create a fake query function "SELECT 1", and run it in upper level function for specific time (e.g. before mysql wait_timeout is triggerred, like every 20 mins). This one will use mysql timeout to close the connection. It is kind of waste mysql resource.

Related

Jdbc connection using java

I have Rest-Api in the java.
That will take dbUrl, dbUserName, dbPassWord, dbDriver and sql query
and gives me the result set and after I will be converting into json format.
Class.forName("oracle.jdbc.driver.OracleDriver");
connectionUrl = "jdbc:oracle:thin:#" + server + ":" + dbName + "";
conn = DriverManager.getConnection(connectionUrl, userName, password);
try {
stmt = conn.createStatement();
output = resultSetHandler(stmt.executeQuery(query)); // this method convert ResultSet to Json
} catch (SQLException e) {
throw new Error(e);
} finally {
if (stmt != null) {
stmt.close();
}
}
} catch (SQLException e) {
throw new Error(e);
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
throw new Error(ex);
}
}
The problem here is that When 30 users use this api at one time means It will throw an error for few users....
and also I will not be using just oracle and I will be using postgres, mysql also
Consider using DB connection pool such as Hikari or C3P0 (both available at Maven Repository). Opening a connection every time is very inefficient and you may run out of connections which may be the error you are getting. Please post your error.
Use try-with-resources instead of doing the finally block. It will automatically call close() on Autoclosable objects such as Connection, Statement, PreparedStatement, ResultSet, etc.
try (
Connection myConnection = MyConnectionPool.getConnection();
Statement stmt = myConnection.createStatement();
ResultSet rs = stmt.executeQuery(query)
) {
// Do work with rs
}

Returning a ResultSet

I am trying to create a method from where I can query my database and retrieve a whole table.
Currently, it works just fine if I use the data inside the method. However, I want the method to return the results.
I'm getting a java.sql.SQLException: Operation not allowed after ResultSet closed on the current code.
How can I achieve this?
public ResultSet select() {
con = null;
st = null;
rs = null;
try {
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery("SELECT * FROM biler");
/*
if (rs.next()) {
System.out.println(rs.getString("model"));
}*/
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
return rs;
}
You should never pass a ResultSet around through public methods. This is prone to resource leaking because you're forced to keep the statement and the connection open. Closing them would implicitly close the result set. But keeping them open would cause them to dangle around and cause the DB to run out of resources when there are too many of them open.
Map it to a collection of Javabeans like so and return it instead:
public List<Biler> list() throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<Biler> bilers = new ArrayList<Biler>();
try {
connection = database.getConnection();
statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
resultSet = statement.executeQuery();
while (resultSet.next()) {
Biler biler = new Biler();
biler.setId(resultSet.getLong("id"));
biler.setName(resultSet.getString("name"));
biler.setValue(resultSet.getInt("value"));
bilers.add(biler);
}
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return bilers;
}
Or, if you're on Java 7 already, just make use of try-with-resources statement which will auto-close those resources:
public List<Biler> list() throws SQLException {
List<Biler> bilers = new ArrayList<Biler>();
try (
Connection connection = database.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, name, value FROM Biler");
ResultSet resultSet = statement.executeQuery();
) {
while (resultSet.next()) {
Biler biler = new Biler();
biler.setId(resultSet.getLong("id"));
biler.setName(resultSet.getString("name"));
biler.setValue(resultSet.getInt("value"));
bilers.add(biler);
}
}
return bilers;
}
By the way, you should not be declaring the Connection, Statement and ResultSet as instance variables at all (major threadsafety problem!), nor be swallowing the SQLException at that point at all (the caller will have no clue that a problem occurred), nor be closing the resources in the same try (if e.g. result set close throws an exception, then statement and connection are still open). All those issues are fixed in the above code snippets.
If you don't know what you want of the ResultSet on retrieving time I suggest mapping the complete thing into a map like this:
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
Map<String, Object> row = null;
ResultSetMetaData metaData = rs.getMetaData();
Integer columnCount = metaData.getColumnCount();
while (rs.next()) {
row = new HashMap<String, Object>();
for (int i = 1; i <= columnCount; i++) {
row.put(metaData.getColumnName(i), rs.getObject(i));
}
resultList.add(row);
}
So basically you have the same thing as the ResultSet then (without the ResultSetMetaData).
Well, you do call rs.close() in your finally-block.
That's basically a good idea, as you should close all your resources (connections, statements, result sets, ...).
But you must close them after you use them.
There are at least three possible solutions:
don't close the resultset (and connection, ...) and require the caller to call a separate "close" method.
This basically means that now the caller needs to remember to call close and doesn't really make things easier.
let the caller pass in a class that gets passed the resultset and call that within your method
This works, but can become slightly verbose, as you'll need a subclass of some interface (possibly as an anonymous inner class) for each block of code you want to execute on the resultset.
The interface looked like this:
public interface ResultSetConsumer<T> {
public T consume(ResultSet rs);
}
and your select method looked like this:
public <T> List<T> select(String query, ResultSetConsumer<T> consumer) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(url, user, password);
st = con.createStatement();
rs = st.executeQuery(query);
List<T> result = new ArrayList<T>();
while (rs.next()) {
result.add(consumer.consume(rs));
}
} catch (SQLException ex) {
// logging
} finally {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
return rs;
}
do all the work inside the select method and return some List as a result.
This is probably the most widely used one: iterate over the resultset and convert the data into custom data in your own DTOs and return those.
As everyone before me said its a bad idea to pass the result set. If you are using Connection pool library like c3p0 then you can safely user CachedRowSet and its implementation CachedRowSetImpl. Using this you can close the connection. It will only use connection when required. Here is snippet from the java doc:
A CachedRowSet object is a disconnected rowset, which means that it makes use of a connection to its data source only briefly. It connects to its data source while it is reading data to populate itself with rows and again while it is propagating changes back to its underlying data source. The rest of the time, a CachedRowSet object is disconnected, including while its data is being modified. Being disconnected makes a RowSet object much leaner and therefore much easier to pass to another component. For example, a disconnected RowSet object can be serialized and passed over the wire to a thin client such as a personal digital assistant (PDA).
Here is the code snippet for querying and returning ResultSet:
public ResultSet getContent(String queryStr) {
Connection conn = null;
Statement stmt = null;
ResultSet resultSet = null;
CachedRowSetImpl crs = null;
try {
Connection conn = dataSource.getConnection();
stmt = conn.createStatement();
resultSet = stmt.executeQuery(queryStr);
crs = new CachedRowSetImpl();
crs.populate(resultSet);
} catch (SQLException e) {
throw new IllegalStateException("Unable to execute query: " + queryStr, e);
}finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
LOGGER.error("Ignored", e);
}
}
return crs;
}
Here is the snippet for creating data source using c3p0:
ComboPooledDataSource cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("<driver class>"); //loads the jdbc driver
} catch (PropertyVetoException e) {
e.printStackTrace();
return;
}
cpds.setJdbcUrl("jdbc:<url>");
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);
javax.sql.DataSource dataSource = cpds;
You can use the CachedRowSet object that is just for what you want:
public CachedRowSetImpl select(String url, String user, String password) {
CachedRowSetImpl crs = null;
try (Connection con = DriverManager.getConnection(url, user, password);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM biler");) {
crs = new CachedRowSetImpl();
crs.populate(rs);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(MySQL.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
return crs;
}
You can read the documentation here:
https://docs.oracle.com/javase/7/docs/api/javax/sql/rowset/CachedRowSet.html
You're closing the ResultSet and consequently you can't use it anymore.
In order to return the contents of the table, you'll have to iterate through the ResultSet and build a per-row representation (in a List, perhaps?). Presumably each row represents some entity, and I would create such an entity for each row.
while (rs.next()) {
list.add(new Entity(rs));
}
return list;
The alternative is to provide some callback object, and your ResultSet iteration would call on that object for each ResultSet row. That way you don't need to build an object representing the whole table (which may be a problem if it's sizable)
while (rs.next()) {
client.processResultSet(rs);
}
I would be reluctant to let clients close the result set/statement/connection. These need to be managed carefully to avoid resource leaks, and you're much better off handling this in one place (preferably close to where you open them!).
Note: You can use Apache Commons DbUtils.closeQuietly() to simply and reliably close the connect/statement/resultset tuple (handling nulls and exceptions properly)
It is bad practice to return result set ,secondly you are already closing it so after closing it you can not use it anymore.
I would suggest using Java 7 with multiple resource in try block will helpful you as suggested above.
If you want entire table result ,you should return its output rather than resultSet.
Assuming you can afford storing the entire result in memory, you may simply return some table-like structure. Using Tablesaw for instance, simply do
Table t = Table.read().db(rows);
with rows a standard java.sql.ResultSet. For details see here. Tablesaw becomes especially useful if you intend to slice-and-dice your data further as it gives you Pandas-like functionality.

BoneCP Statement Handle Cannot Be Cast JDBC

I am trying to setup a boneCP connection and I am getting the following error message:
Exception in thread "main" java.lang.ClassCastException: com.jolbox.bonecp.StatementHandle cannot be cast to com.mysql.jdbc.Statement
The connection seems to work fine but I get stopped out at the query.
Here is my code:
BoneCP connectionPool = null;
Connection connection = null;
try {
// load the database driver (make sure this is in your classpath!)
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
// setup the connection pool
BoneCPConfig config = new BoneCPConfig();
config.setJdbcUrl("jdbc:mysql://192.126.0.0:3306/"); // jdbc url specific to your database, eg jdbc:mysql://127.0.0.1/yourdb
config.setUsername("root");
config.setPassword("");
config.setMinConnectionsPerPartition(5);
config.setMaxConnectionsPerPartition(10);
config.setPartitionCount(1);
connectionPool = new BoneCP(config); // setup the connection pool
connection = connectionPool.getConnection(); // fetch a connection
if (connection != null){
System.out.println("Connection successful!");
Statement stmt = (Statement) connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1 FROM table"); // do something with the connection.
while(rs.next()){
System.out.println(rs.getString(1)); // should print out "1"'
}
}
connectionPool.shutdown(); // shutdown connection pool.
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
This is quite simple: If you use BoneCP, you do not have direct access to the objects of the underlying driver. This applies to connection pools in general, because they usually object proxies to handle resource management (eg close statements, resultsets etc when the connection is returned to the pool). This especially applies to statements as connection pools can (and usually do) also provide statement caching.
Specifically for BoneCP you should be able to get to the wrapped statement using StatementHandle.getInternalStatement() (although I am not 100% sure about that).
Although the big question is: why do you need to cast to com.mysql.jdbc.Statement, isn't the java.sql.Statement interface sufficient for you?

JDBC result set from an Oracle PL/SQL stored procedure

What does oracleClose() and oracleCloseQuery() do in sqlj.runtime.ExecutionContext.OracleContext.
Since we upgraded jdbc driver jar to ojdbc5.jar with the oracleClose() in the finally block we get the below exception when using resultset.next() and not with oracleCloseQuery(). Is it safe to use oracleCloseQuery(). The database is Oracle 11g and WAS 6.1.X.X. Appreciate your response.
Here is the error message :
java.sql.SQLException: Closed Statement: next
at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:131)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:197)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:261)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:269)
at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:205)
at com.westgroup.pubsvc.rms.models.ResultSetSRC.getNextResult(ResultSetSRC.java:112)
The exception is telling you that the Statement which has returned this ResultSet is been closed while you're attempting to iterate over the ResultSet. This indicates that you're using ResultSet outside the try block where the Statement is been executed and that you're probably using the ResultSet as return value of the method. This is a bad practice.
I'd suggest you to rewrite your JDBC code so that the ResultSet is been processed in the very same try block as the Statement is been executed, or that the methods returns something like as List<Entity> instead of a ResultSet.
Here's a kickoff example of the correct JDBC idiom:
public List<Entity> list() throws SQLException {
// Declare resources.
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
List<Entity> entities = new ArrayList<Entity>();
try {
// Acquire resources.
connection = database.getConnection();
statement = connection.createStatement("SELECT id, name, value FROM entity");
resultSet = statement.executeQuery();
// Gather data.
while (resultSet.next()) {
Entity entity = new Entity();
entity.setId(resultSet.getLong("id"));
entity.setName(resultSet.getString("name"));
entity.setValue(resultSet.getInteger("value"));
entities.add(entity);
}
} finally {
// Close resources in reversed order.
if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
// Return data.
return entities;
}
By the way, you don't need Oracle JDBC driver specific classes/methods here. It's all just java.sql.*. This way you keep the JDBC code portable among databases.

Which should I close first, the PreparedStatement or the Connection?

When using a PreparedStatement in JDBC, should I close the PreparedStatement first or the Connection first? I just saw a code sample in which the Connection is closed first, but it seems to me more logical to close the PreparedStatement first.
Is there a standard, accepted way to do this? Does it matter? Does closing the Connection also cause the PreparedStatement to be closed, since the PreparedStatement is directly related to the Connection object?
The statement. I would expect you to close (in order)
the result set
the statement
the connection
(and check for nulls along the way!)
i.e. close in reverse order to the opening sequence.
If you use Spring JdbcTemplate (or similar) then that will look after this for you. Alternatively you can use Apache Commons DbUtils and DbUtils.close() or DbUtils.closeQuietly().
The following procedures should be done (in order)
The ResultSet
The PreparedStatement
The Connection.
Also, it's advisable to close all JDBC related objects in the finally close to guarantee closure.
//Do the following when dealing with JDBC. This is how I've implemented my JDBC transactions through DAO....
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = ....
ps = conn.prepareStatement(...);
//Populate PreparedStatement
rs = ps.executeQuery();
} catch (/*All relevant exceptions such as SQLException*/Exception e) {
logger.error("Damn, stupid exception: " , e);
} finally {
if (rs != null) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
logger.error(e.getMessage(), e.fillInStackTrace());
}
}
if (ps != null) {
try {
ps.close();
ps = null;
} catch (SQLException e) {
logger.error(e.getMessage(), e.fillInStackTrace());
}
}
try {
if (conn!= null && !conn.isClosed()){
if (!conn.getAutoCommit()) {
conn.commit();
conn.setAutoCommit(true);
}
conn.close();
conn= null;
}
} catch (SQLException sqle) {
logger.error(sqle.getMessage(), sqle.fillInStackTrace());
}
}
You can see I've checked if my objects are null and for connection, check first if the connection is not autocommited. Many people fail to check it and realise that the transaction hasn't been committed to DB.

Categories