Im new in java and SQL, Im repeating a problem that i don't know how to avoid it:
assume i want to make two executeQuery, one inside the other in the getRequestsFromDB method i make the first executeQuery and in the second method isProfessionalHasThatProfession i make the second executeQuery:
private Vector<ClientRequest> getRequestsFromDB() throws SQLException {
Vector<ClientRequest> retVal = new Vector<ClientRequest>();
ResultSet result = null;
try {
for (int i=0 ; i<_userBean.getProfession().length ; ++i ){
result = _statement.executeQuery("SELECT * FROM "+_dbName+"."+CLIENTS_REQUEST_TABLE+" WHERE "+CLIENTS_REQUEST_T_PROFESSION+"='"+_userBean.getProfession()[i]+"'");
while(result.next()){ //HERE IN THE SECOND LOOP GETTING NULL EXCEPTION
if(isProfessionalHasThatProfession(result.getString(CLIENTS_REQUEST_T_PROFESSION))){
retVal.add(cr);
ClientRequest cr = new ClientRequest
(result.getString(CLIENTS_REQUEST_T_CLIENT_ID),
result.getString(CLIENTS_REQUEST_T_CITY),
result.getString(CLIENTS_REQUEST_T_DATE),
result.getString(CLIENTS_REQUEST_T_PROFESSION));
}
}
}
} catch (SQLException ex) {
throw ex;
}
return retVal;
}
the second function:
private boolean isProfessionalHasThatProfession(String profession) throws SQLException {
ResultSet result = null;
try {
result = _statement.executeQuery("SELECT "+WORKER_PROFESSIONS_T_PROFESSION+" FROM "+_dbName+"."+WORKER_PROFESSIONS_TABLE+" WHERE "+WORKER_PROFESSIONS_T_PROFESSIONAL_ID+"='"+_userBean.getProId()+"'");
while(result.next()){
if(result.getString(1).equals(profession)){
return true;
}
}
} catch (SQLException ex) {
throw ex;
}
return false;
}
in the second loop im getting a SQLException: "operation not allowed after ResultSet closed", i have tried:
close in finally the result with result.close() but also i get exception null pointer exception.
i'm really don't know how to deal with that, ideas?
Thank You!
youre reusing _statement (which i assume is global?) to get 2 different ResultSets, but then you return to the 1st ResultSet (in the outside function) after you got the 2nd (inside the inner function, which automatically closed the 1st) - try using 2 separate statements
Check this link :http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Statement.html
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
And you are reusing your statement
See this quote, from the ResultSet API:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
Looks like you are using a class, or global, scope Statement (_statement), which backs both the resultset you are trying to iterate over, and query details of some sort for each entry in the resultset in your isProfessionalHasThatProfession method. but when you execute a new query with the same Statement, your old ResultSet is closed.
So, you'll need a separate statement for the second query.
From the Java API:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects.
So you have to generate a new Statement for the second ResultSet. Please don't forget to close the Statements respectively.
Related
I have two methods in my class, First I am calling method dbExecuteStatement(), which execute the sql query. After execution of sql query, I get a ResultSet object. I am saving this ResultSet object in a static hashMap, so that on my next method call fetchResults(), I can use the existing result set to retrieve the results. Reason for saving the ResultSet object in a map is ,in fetchResults() method request parameter, I will get the max fetch row size, and on basis of that value I will be iterating the result set. Both of this methods are supposed to be called individual from the client side.
Now the problem, I am facing is that, When I am iterating the ResultSet object in fetchResults() method, I am getting the row count zero. If I fetch the same ResultSet from a hashMap in dbExecuteStatement(), I get the actual row count i.e 5 in my case. I checked the ResultSet object that I have put in the hash map in fetchResults() method and dbExecuteStatement(), it is the same object. But If get the ResultSetMetaData object in fetchResults() method and dbExecuteStatement(), they are coming different. Can someone help me in understanding the cause, Why I am getting the result count zero.
Below is the code:
public class HiveDao1 {
private static Map<Object,Map<Object,Object>> databaseConnectionDetails
= new HashMap<Object,Map<Object,Object>>();
//This method will execute the sql query and will save the ResultSet obj in a hashmap for later use
public void dbExecuteStatement(DbExecuteStatementReq dbExecuteStatementReq){
//I already have a connection object saved in map
String uniqueIdForConnectionObject = dbExecuteStatementReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
Connection connection = (Connection) dbObject.get(DatabaseConstants.CONNECTION);
try {
Statement stmt = connection.createStatement() ;
// Execute the query
ResultSet resultSet = stmt.executeQuery(dbExecuteStatementReq.getStatement().trim()) ;
//save the result set for further use, Result set will be used in fetchResult() call
dbObject.put(DatabaseConstants.RESULTSET, resultSet);
/*
* Now below is the debugging code,which I put to compare the result set
* iteration dbExecuteStatement() and fetchResults method
*/
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("==ResultSet fethced in dbExecuteStatement=="+rs);
System.out.println("==ResultSet metadata fetched in dbExecuteStatement ==="+rs.getMetaData());
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
System.out.println("No of rows found from result set in dbExecuteStatement is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* This method fetch the result set object from hashMap
* and iterate it on the basis of fetch size received in req parameter
*/
public void fetchResults(FetchResultsReq fetchResultsReq){
String uniqueIdForConnectionObject = fetchResultsReq.getDbUniqueConnectionHandlerId();
Map<Object,Object> dbObject = databaseConnectionDetails.get(uniqueIdForConnectionObject);
try {
//Fetch the ResultSet object that was saved by dbExecuteStatement()
ResultSet rs = (ResultSet) dbObject.get(DatabaseConstants.RESULTSET);
ResultSetMetaData md = (ResultSetMetaData) dbObject.get(DatabaseConstants.RESULTSETMETADATA);
System.out.println("ResultSet fethced in fetchResults at server side dao layer======"+rs);
System.out.println("ResultSet metadata fetched in fetchResults at server side dao layer======"+md);
int count = 0;
while (rs.next()) {
++count;
}
if (count == 0) {
System.out.println("No records found");
}
//Here the row count is not same as row count in dbExecuteStatement()
System.out.println("No of rows found from result set in fetchResults is "+count);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Expanding on my comment (And #Glenn's):
Using a ResultSet more than once
When you write debug code that iterates a ResultSet, the cursor moves to the end of the results. Of course, if you then call the same object and use next(), it will still be at the end, so you won't get any more records.
If you really need to read from the same ResultSet more than once, you need to execute the query such that it returns a scrollable ResultSet. You do this when you create the statement:
Statement stmt = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY );
The default statement created by connection.createStatement() without parameters returns a result set of type ResultSet.TYPE_FORWARD_ONLY, and that ResultSet object can only be read once.
If your result set type is scroll insensitive or scroll sensitive, you can use a statement like rs.first() to reset the cursor and then you can fetch the records again.
Keeping the statement in scope
#Glenn's comment is extremely important. The way your program works right now, it may work fine throughout the testing phase, and then suddenly in production, you'll sometimes have zero records in your ResultSet, and the error will be reproducible only occasionally - a debug nightmare.
If the Statement object that produces the ResultSet is closed, the ResultSet itself is also closed. Since you are not closing your Statement object yourself, this will be done when the Statement object is finalized.
The stmt variable is local, and it's the only reference to that Statement that we know of. Therefore, it will be claimed by the garbage collector. However, objects that have a finalizer are relegated to a finalization queue, and there is no way of knowing when the finalizer will be called, and no way to control it. Once it happens, the ResultSet becomes closed out of your control.
So be sure to keep a reference to the statement object alongside your ResultSet. And make sure you close it properly yourself once you are done with the ResultSet and will not be using it anymore. And after you close it remember to remove the reference you have kept - both for the statement and the result set - to avoid memory leaks. Closing is important, and relying on finalizers is a bad strategy. If you don't close it yourself, you might run out of cursors at some point in your database (depending on the DBMS and its configuration).
I have a question regarding ResultSet objects in Java and recursion.
I was working on some code for university and whenever I found a descendant I recursed on with that new node but when I came out of the recursion and tried to rs.next() the pointer had gone from pointing to row 1 back to row 0 and when it hit row 0 the rs.next() failed and it returned! I knew there was one thing in there that it hadn't read yet! What is it that causes this?
The only way I got round that problem was to go through the resultset and get every element and add it into an array list, then loop through the arraylist doing the recursion on each element in the array! Surely this must be a better way around this?
This is the new code I'm using
private Vector<String> getDescendents(String dogname, Vector<String> anc) {
if (anc == null) anc = new Vector<String>();
ArrayList<String> tempList = new ArrayList<String>(2);
try {
System.out.println("Inside ");
childStmt.setString(1,dogname);
childStmt.setString(2,dogname);
ResultSet rs = childStmt.executeQuery();
System.out.println("Before while "+rs.getRow());
while (rs.next()){
String col1 = rs.getString(1);
tempList.add(col1);
anc.add(col1);
}
for (String s:tempList){
getDescendents(s,anc);
}
}
catch(Exception e) {
doError(e, "Failed to execute ancestor query in getBreeding");
}
return anc;
}
However before this, I had the getDescendents call inside the while loop and thus no for loop and no arraylist either, but whenever it actually recursed it would loose track of the resultset when it returned out of the recursion.
Further details :
When I used the debugger (nearly said gdb there lol far too much C) the ID of the result set was the same but the row pointer had returned to 0 and the rs.next call failed!
Once again any explanation is appreciated!
p.s it previously looked like
private Vector<String> getDescendents(String dogname, Vector<String> anc) {
if (anc == null) anc = new Vector<String>();
ArrayList<String> tempList = new ArrayList<String>(2);
try {
System.out.println("Inside ");
childStmt.setString(1,dogname);
childStmt.setString(2,dogname);
ResultSet rs = childStmt.executeQuery();
System.out.println("Before while "+rs.getRow());
while (rs.next()){
String col1 = rs.getString(1);
anc.add(col1);
getDescendendts(col1,anc);
}
}
catch(Exception e) {
doError(e, "Failed to execute ancestor query in getBreeding");
}
return anc;
}
It looks like you're re-using childStmt; don't do this. From the Statement javadoc:
By default, only one ResultSet object per Statement object can be open
at the same time. Therefore, if the reading of one ResultSet object is
interleaved with the reading of another, each must have been generated
by different Statement objects. All execution methods in the Statement
interface implicitly close a statment's current ResultSet object if an
open one exists.
You'll have to either save all the rows first, then do the recursive query, or create a new Statement for each ResultSet you want to fetch.
My program is get terminated just after printing hello in getImportance beg. Why so? My MAIL table has values.
Connection connection = connectToDatabase();
Statement stmt = connection.createStatement();
ResultSet mailset = stmt.executeQuery("SELECT SUBJECT from MAIL");
ResultSet keywordset = stmt.executeQuery("SELECT SKEYWORD FROM KEYWORD");
System.out.println("hello in getImportance beg");
while(mailset.next())
{
System.out.println("hello in first while");
while(keywordset.next())
{
System.out.println("hello in second while");
if(mailset.getString("SUBJECT").equals(keywordset.getString("SKEYWORD")));
{
System.out.println("hello in if");
stmt.executeUpdate("UPDATE KEYWORD SET IMPORTANCE = IMPORTANCE'" + 1 + "'");
stmt.executeUpdate("COMMIT");
}
}
}
mailset.close();
keywordset.close();
connection.close();
What am I missing?
Thanks!
Thanks everyone for the replies. Defining the second ResultSet after first while did the trick.
Your while loop is obviously not running.
Check the result of mailset.next()
The problem is probably that you are trying to obtain two ResultSets from a single Statement.
From the java.sql.Statement documentation: "By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists."
The problem may be the mailset. it delivers probably no result. You can check it with System.out.println(mailset.next()); before the first loop, or debug it.Another issue on the second resultset. As I understand: you try to iterate each time over keywordset. Then you need to go to the beginning of the result set after the second while loop (while(keywordset.next()) using keywordset.beforeFirst() .
I am using a SELECT statement to get data from a table and then insert it into another table. However the line "stmt.executeQuery(query);" is inserting the first line from the table then exits. When I comment this line out, the while loop loops through all the lines printing them out. The stacktrace isn't showing any errors. Why is this happening?
try{
String query = "SELECT * FROM "+schema_name+"."+table;
rs = stmt.executeQuery(query);
while (rs.next()) {
String bundle = rs.getString("BUNDLE");
String project_cd = rs.getString("PROJECT_CD");
String dropper = rs.getString("DROPPER");
String week = rs.getString("WEEK");
String drop_dt = rs.getString("DROP_DT").replace(" 00:00:00.0","");
query = "INSERT INTO INDUCTION_INFO (BUNDLE, PROJECT_CD, DROPPER, WEEK, DROP_DT) "
+ "VALUES ("
+ bundle+","
+ "'"+project_cd+"',"
+ dropper+","
+ week+","
+ "to_date('"+drop_dt+"','YYYY-MM-DD'))";
System.out.println(query);
stmt.executeQuery(query);
}
}catch(Exception e){
e.printStackTrace();
}
You are re-using the Statement that was used to produce rs on the last line of your loop.
This will close the ResultSet rs. As stated in the documentation:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
You need to use a second Statement object to execute the INSERT statements.
Statement objects can only do one thing at a time, so when you execute that INSERT, you invalidate the ResultSet which it generated. You'll need to create a second Statement object to perform the INSERT.
From the Statement documentation: "By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists."
if you use the same statement, it will invalidate the previous result set. You should use a different statement to perform updates/inserts.
This is from the Java docs of interface Statement:
By default, only one ResultSet object per Statement object can be open
at the same time.
So you better use a second Statement or even better a PreparedStatement.
And to execute an INSERT SQL statement you should use executeUpdate() instead of executeQuery().
First of all, I'm new to Java.
I'm trying to figure out what would be a good/handy way to work with DB from Java. I'm using c3p0 for connection pooling. Hibernate or other ORM is not an option this time, we decided to stick with "plain SQL" for now.
Currently basic retrieval of data looks like this:
private int getUserID(int sessionID, String userIP) {
int result = 0;
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
// Application.cpds is an instance of c3p0's ComboPooledDataSource
conn = Application.cpds.getConnection();
st = conn.prepareStatement("SELECT user_id, user_ip, is_timed_out FROM g_user.user_session WHERE id = ?");
st.setInt(1, sessionID);
rs = st.executeQuery();
if ( rs.next() ) {
if ( !rs.getBoolean("is_timed_out") && userIP.equals(rs.getString("user_ip")) ) {
result = rs.getInt("user_id");
}
}
}
catch (SQLException e) {
e.printStackTrace();
}
finally {
if ( rs != null ) {
try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
}
if ( st != null ) {
try { st.close(); } catch (SQLException e) { e.printStackTrace(); }
}
if ( conn != null ) {
try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
return result;
}
The code looks very long for such a basic operation. Another problem is that most of the code would have to be repeated in many places (declaring Connection, PreparedStatement, ResultSet, closing them, catching exceptions). Though, this is what I see in most examples when googling.
In PHP I would create a wrapper class that would have method select() that accepts 2 arguments (string)sqlQuery and (array)parameters and would return simple array of data. Wrapper class would also have few more specific methods, like:
selectValue() for single value (e.g., select count(*) from user)
selectRow() for single row (e.g., select name, surname from user where id = :user_id)
selectColumn for single column (e.g., select distinct remote_address from user)
Is anything like this practiced in Java? Or is there anything better / handier? Or should I use same style as in getUserID() example above? As I said, ORM is not an option this time.
Thanks in advance :)
edit: Currently DBConnection class is written. It gets connection from c3p0 connection pool in constructor. It has few public methods for working with DB: select() for tabular data, selectValue() for single value, selectRow() and selectColumn() for single row or column, as well as insert(), update(), delete() and ddl(). Methods accept String query, Object[] params arguments, with params being optional. insert(), update() and delete() return Integer which is result of PreparedStatement.executeUpdate(). select methods return different results:
ArrayCollection<HashMap<String, Object>> select()
Object selectValue()
HashMap<String, Object> selectRow()
ArrayCollection<Object> selectColumn()
The last problem is with compiler warnings - "warning: [unchecked] unchecked cast". This is because all methods call single private method that returns Object and cast its result to mentioned types. As I am new to Java, I'm also not sure if I have chosen appropriate types for selects. Other than that, everything seems to work as expected.
If the an ORM is no option, you could still use Spring's JDBC helper classes:
http://docs.spring.io/spring-framework/docs/4.1.0.RELEASE/spring-framework-reference/html/jdbc.html
Or you could simply write some helper methods on your own. Maybe a DBUtil.close(conn, st, rs); would be nice.
And by the way, you really should use a logging framework instead of "e.printStackTrace()"
EDIT:
One more thing: I think it's kind of hard to add ORM afterwards, when you have all the SQL already written in plain JDBC. You can't refactor that stuff, you have to throw it away and do it again.
EDIT:
You don't have to close the resultSet if you are closing the statement anyway. The Java ResultSet API reads:
A ResultSet object is automatically
closed when the Statement object that
generated it is closed, re-executed,
or used to retrieve the next result
from a sequence of multiple results.
Beside that, C3P0 does resource management as well and and closes Statements when you return a connection. You might to look that up too.
To avoid the repetition of code and perhaps makes things simpler.
What you could do is create a Database class.
In the class you could then create general purpose methods for access to the database.
For eg.
if the class is called DBManager.java then inside
create methods
private connect()
public boolean update()
public ResultSet query()
Reason for connect method is obvious, you use it get your connection. Since its private you call it in the constructor of DBManager.
You then use your update() method to allow you to perform SQL inserts,update,delete and the like, basically any SQL operation that doesn't return any data except for maybe a status of its success is done with the update method.
Your query method is used when you want to do a select query. You can thn return the resultset and then iterate through the results in the calling method/class
How you handle exceptions is up to you. It may be nicer on you to handle exceptions in the DBManager class that way you won't have to handle them in the various classes that you make a query from.
So instead of
public ResultSet query() Throws SQLException{
you would use a try catch inside the query method like you did in your examples above.
The obvious advantage of handling it in the dbmanager class is that you won't have to worry about it in all the other classes that make use of your sql connection.
Hope that's helpful
in response to your comment:
Its up to you what you return, the ResultSet being return is only an idea but maybe it'd be best to return a collection of some sort instead of an array, maybe? depending on what you need. The resultset needn't be closed.
public ResultSet query(String strSql) {
try {
Statement tmpStatement = connection.createStatement();
ResultSet resultSet = tmpStatement.executeQuery(strSql);
return resultSet;
} catch (java.sql.SQLException ex) {
//handle exception here
return null;
}
}
your update can then look like so
public boolean updateSql(String strSQL) {
try {
Statement tmpStatement = connection.createStatement();
tmpStatement.executeUpdate(strSQL);
return true;
} catch (java.sql.SQLException ex) {
//handle exception
return false;
}
}
erm, you can then use your query method like so
ResultSet r = query(sql);
try {
while (r.next()) {
someVar[i] = r.getString("columnName");
}
} catch (SomeException ex) {
//handle exception etc
}
But then again as you said instead of returning a result set you could change the query method to copy your results to an array or collection and then return the collection and close the statement with
tmpStatement.close();
But when a Statement object is closed, its current ResultSet object, if one exists, is also closed.(from api docs)
Its good practice to free up database resources as soon as so copying your result to a collection object and then closing your statement is probably best. Again its up to you.
" Hibernate or other ORM is not an option this time, we decided to stick with "plain SQL" for now."
Out of curiosity, what was the reason to stick with plain SQL? Looking at the example and question you mentioned first obvious answer would be use ORM and don't bother - in most cases standard ORM feature list would be sufficient.
Obviously there are plenty of reasons not to use ORM's, so I'm interested in yours?
I think the level o granularity is always a developer decision. I mean, the great thing of having so many exceptions and validations is that you can capture the specific error and act according to it, however if what you need doesn't require that level of robustness and as you are showing it is just to print out the stack trace, I think a wrapper method can be useful in your case.