We have a Java class which loops through a result set, which contains Store information, and then starts processing ascii files for each respective stores. For each store to process the ascii file takes around 5 minutes. The issue we encountered is after it processes the first store's ascii file and then fetches the next result set, we get a SQLException saying "DSRA9110E: ResultSet is closed".
Our code basically looks like this.
private void startProcess() throws Exception {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement("SELECT STORE_CODE FROM STORE");
rs = pstmt.executeQuery();
while (rs != null && rs.next()) {
System.out.println("Processing store " + rs.getString("STORE_CODE"));
try {
processStoreSalesFile();
} catch (Exception e) {
conn.rollBack();
e.printStackTrace();
}
if (rs != null) {
System.out.println("ResultSet is not null");
}
}
} finally {
if (rs != null) {
rs.close();
rs = null;
}
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
}
}
When the error occurs, I do see the system printline "ResultSet is not null". But when it gets the next ResultSet, it says ResultSet is closed.
I have tried to comment out the code which calls processStoreSalesFile() and we didn't get this error and it is able to fetch the next ResultSet without throwing any exceptions.
The next attempt I tried is to uncomment the call to the method processStoreSalesFile() and then remove any ascii files from the file system so that the program will have nothing to process. And no exceptions thrown also.
Our setup is WebSphere-Informix. We have another setup WebSphere-Oracle and that didn't have any problems.
The thing I am suspecting is the ResultSet has timedout or it just didn't want to wait for the process to finish and closed by itself.
Update 1:
Inside the processStoreSalesFile() method, there's a conn.commit() call to commit the records. Is it when a commit is called, the ResultSet will be closed? At the WAS admin console, I've already added the data source property resultSetHoldability with the value '1'. But still the ResultSet is closed.
I hope someone can help me here :(
Thanks.
Here is what we did which worked. Initially, Websphere was configured to use the Informix JDBC driver as its data source, since we are connecting to an Informix database. We changed it to use the DB2 JCC Driver (as proposed by the IBM Informix tech support) and then in the data source custom property, we set the 'resultHoldability' value to '1' (HOLD_CURSORS_OVER_COMMIT). Re-ran the program and it managed to loop through all the results in the result set.
You could use pstmt.setQueryTimeout(seconds). Make sure oracle driver support this. For more detail
here
Related
I try to create a connection between JDBC and MS Access.
I follow the instruction as per this link. I am using IntelliJ Idea. Here I am sharing some snaps to describe my problem.
This is the code that I write down to make a connection with Database Database2. But as you can see there is no error neither any output. Now I am sharing the table structure and content on the table.
2nd picture is
My code is:
import java.sql.*;
public class Connection_sample {
public static void main(String[] args) {
try {
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
Connection conn= DriverManager.getConnection("jdbc:ucanaccess://D://tutorial/Database2.accdb");
Statement s = conn.createStatement();
s.executeQuery("select * from Student");
ResultSet rset = s.getResultSet();
while (rset.next()) {
System.out.println(rset.getInt(1)+""+rset.getInt(2));
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Can anyone help me to find the error?
Your problem is the result of using getResultSet() instead of using the result set returned by executeQuery(). You should only use getResultSet() in combination with execute().
A result set should only be obtained once, and it was already returned from executeQuery (which you ignored). When you called getResultSet, you - apparently - got an empty one (which technically violates the contract).
I am working on a JAVA program which need to update database from text files. I have successfully inserted and updated data. But i am facing a problem with here, this method. Query runs without error and giving me the response. But the database table is not updating.
private void filteData() {
System.out.println("filteData");
Statement statementAtenLogInsert = null;
Statement statementqCheck = null;
Statement statementUpdateProLog = null;
Statement statementEnterError = null;
ResultSet rs = null;
int rcount;
//Update successfull attendance_test
String attenLogInsertSuccess = "INSERT INTO attendance_log (user_id, check_in, check_out) SELECT user_id, check_in, check_out FROM process_log WHERE flag = 'S'";
try {
statementAtenLogInsert = connection.createStatement();
statementAtenLogInsert.execute(attenLogInsertSuccess);
int qSuccess = statementAtenLogInsert.executeUpdate(attenLogInsertSuccess);
System.out.println("qSuccess " + qSuccess);
if(qSuccess > 0){
String deleteProcessLog = "DELETE FROM process_log WHERE flag = 'S'";
statementAtenLogInsert.execute(deleteProcessLog);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Here the attenLogInsertSuccess and deleteProcessLog queries are not working. Mean nothing happened from database table side. But qSuccess giving me a value. That means attenLogInsertSuccess is triggering. But nothing happened from mysql side.
You need to close your connection in order to flush the changes to the database.
Try adding connection.close(); somewhere in your pipeline, typically you close the connection in a finally block to ensure it is always closed but it appears you have defined your connection elsewhere, presumably for re-use in the calling function.
You also need to close your statements before closing the connection. See this similar answer for the pattern.
I have a problem with closing a connection to MySQL.
I'm getting the error:
java.sql.SQLException: Operation not allowed after ResultSet closed
My code:
public static ResultSet sqlquery (String query)
{
ResultSet rs=null;
Connection connection=null;
Statement st=null;
try{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("databaseadress","username","password");
st = connection.createStatement();
rs = st.executeQuery(query);
}catch(SQLException e){System.out.println("SQL error: " + e);}
catch(Exception e){System.out.println("Error: " + e);}
finally {
try{
if(rs != null) rs.close();
if(st!= null) st.close();
if(connection != null) connection.close();
}catch(SQLException e){System.out.println("SQL error : " + e);}
}
return rs;
}
JDBC doesn't bring back all the results of a query in a ResultSet, because there may be too many of them to fetch them all eagerly. Instead it gives you something you can use to retrieve the results, but which goes away when the connection closes. So when you pass it back from your method after closing the database connection, nothing else can use it.
What you can do instead is to have this method use the resultSet to populate an object or a collection of objects, and pass that populated object back.
If you change your code to pass in a rowMapper (that takes a resultSet and passes back an object populated with the current row in the resultset), and use that to populate a container object that you pass back, then you'll have something as reusable as what what you've written, but which actually works because it doesn't depend on having the connection held open after the call is finished.
Here's your example code rewritten to use the rowmapper, get rid of some unnecessary exception-catching, and fix a bug that will prevent the connection from getting closed in some cases:
public static List<T> sqlquery (String query, RowMapper<T> rowMapper) throws SQLException
{
Connection connection=null;
Statement st=null;
ResultSet rs=null;
// don't need Class.forName anymore with type4 driver
connection = DriverManager.getConnection("databaseadress","username","password");
st = connection.createStatement();
rs = st.executeQuery(query);
List<T> list = new ArrayList<T>();
while (rs.next()) {
list.add(rowMapper.mapRow(rs));
}
// don't let exception thrown on close of
// statement or resultset prevent the
// connection from getting closed
if(rs != null)
try {rs.close()} catch (SQLException e){log.info(e);}
if(st!= null)
try {st.close()} catch (SQLException e){log.info(e);}
if(connection != null)
try {connection.close()} catch (SQLException e){log.info(e);}
return list;
}
If you don't catch each exception thrown on close individually, as shown above, you risk failing to close the connection if either the statement or the resultSet throw an exception on close.
This is similar to what spring-jdbc does, it defines a RowMapper as:
public interface RowMapper<T> {
T mapRow(ResultSet, int rowNum) throws SQLException;
}
The next step is going to be parameterizing your queries so you don't have to
surround parameter values in quotes or worry about sql injection. See this answer for an example of how spring-jdbc handles this. The long term answer here is, it would be better to adopt spring-jdbc or something similar to it than to reinvent it piecemeal.
This is the way JDBC works. In your code you closed the ResultSet and the Connection, after which the ResultSet is no longer usable. If you want it to be usable you must leave it (and the Connection) open.
However, if you return the ResultSet, you should refactor your code so the calling method provides the Connection.
RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet rowset = factory.createCachedRowSet();
rowset.populate(ResultSet data)
/* now you can close you connection and prepare statement*/
Once the connection is closed you can no longer use any of the resources (statements, prepared statements, result sets), all of them are automatically closed. So you need to do all of your processing while the resources are open.
Try filling and returning a DTO, this way you can have the data you need without keeping a connection alive.
In my Java app, I want to query the MySQL status statistics. I'm adding some simple monitoring (mostly writing alerts when certain settings reach certain thresholds).
In any case, I can't get it working using standard JDBC code. I want something like this:
ResultSet s = DBUtil.executeQuery("SHOW STATUS LIKE '%conn%'");
But this isn't working from what I see in the debugger. Any solutions?
Thanks for the link to the documentation. It helped clear up some confusion.
For the record, here's how I navigated the ResultSet properly to find the values I wanted...
String sql = "SHOW GLOBAL STATUS LIKE '%conn%'";
ResultSet rs = null;
try
{
rs = DBUtil.executeQuery(stmt, sql);
while (rs != null && rs.next())
{
if (StringUtils.equals(rs.getString(1), "Max_used_connections"))
return rs.getString(2);
}
}
catch (Exception e)
{
throw e;
}
i'm trying to get the type and the name of the result and when enter in the loop, excuting somo instructions about the metadata the resulset.next changed from true to false, and give the error java.sql.SqlExcepcion exhausted resultset. Any ideas? i really dont know how solved it because i read the post with the solution of this problem and validate if the resultset it's null before begin the loop. I'm called this method with a scheduler of quartz. I'm using this in a j2ee aplication and the example it's this
try
{
InitialContext ctx = new InitialContext();
WrapperDataSource wrapperDataSource = (WrapperDataSource)ctx.lookup(systemLogger.getConfigurationParameters().getDataSource());
conn = wrapperDataSource.getConnection();
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
conn = DriverManager.getConnection(url,login,password);
if (conn != null)
{
stmt = conn.createStatement();
res = stmt.executeQuery(query);
if (res != null)
{
while (res.next())
{
for (int i = 0; i < columnlength; i++)
{
String columnName = metadata.getColumnName(i+1);
if (metadata.getColumnName(i+1).equalsIgnoreCase(systemLogger.getColumnStatus()))
{
columnStatusType = metadata.getColumnType(i+1);
}
else if (metadata.getColumnName(i+1).equalsIgnoreCase(systemLogger.getColumnDocumentId()))
{
columnDocumentIdType = metadata.getColumnType(i+1);
}
else if (metadata.getColumnName(i+1).equalsIgnoreCase(systemLogger.getColumnTimer()))
{
columnTimerType = metadata.getColumnType(i+1);
}
}
}
}
else
{
__log.error("No results found for the query");
throw new PtmServiceException("No se encontraron resultados para el query");
}
}
else
{
__log.error("Could not create the connection");
throw new PtmServiceException("No se pudo crear la conexion");
}
}
catch(Exception e)
{
__log.error("Error in the execution of the query");
throw new PtmServiceException("Error ejecutando la busqueda");
}
finally
{
res.close();
stmt.close();
conn.close();
}
The variable columnlength seems to hold a value larger than the number of columns returned by the query. Try with a smaller columnlength.
finally, i see the problem, while i'm debugging the code with ecplise in the view of the expressions i added the follow expression res.next(), then each sentence that i pass for the step into bring the consequence that expression that evaluate if the resultset has more rows, be evaluated again. In some point the resultset has evaluated all the rows for each step into that i made in the process of debugging. The only thing that i have to do was eliminate the expression and works fine...
The problem might not be with the code but instead could be the database. Double check that the TABLE IS NOT EMPTY. You get this error if the table is empty. Keep in mind that databases like Oracle require a commit after all your insert, update, alter statements .Your changes might not be visible outside the database till you run a commit over the your db, I was having this problem for quite a long time. I kept on checking the table with select statement but the problem with my oracle db was that I had not issued a commit over my db.