JDBC-ResultSet is closed in while-Loop - java

I'm having a really bad time with a ResultSet, which is closed within a while-Loop for iterating this ResultSet. I have know the exact line in which the ResultSet is closed, but i have no idea why.
public LinkedList<Athlet> alleAbrufen () throws SQLException {
LinkedList<Athlet> alleAthleten = new LinkedList<Athlet>();
String abrufenAthleten = "SELECT * FROM Athlet ORDER BY athlet_id";
ResultSet athleten_rs = stmt.executeQuery(abrufenAthleten);
while (athleten_rs.next()) {
long id = athleten_rs.getInt(1);
String name = athleten_rs.getString(2);
LinkedList<Leistung> alleLeistungen = alleAbrufen((int) (id)); //after this line the ResultSet gets closed
alleAthleten.add(new Athlet(id, name, alleLeistungen));
}
return alleAthleten;
}
public LinkedList<Leistung> alleAbrufen(int athlet_id) throws SQLException {
LinkedList<Leistung> alleLeistungen = new LinkedList<Leistung>();
String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id="+athlet_id;
ResultSet rs = stmt.executeQuery(selectLeistungen);
while (rs.next()) {
long id = rs.getInt(1);
String bezeichnung = rs.getString(2);
String datum = rs.getString(3);
double geschwindigkeit = rs.getDouble(4);
boolean selectedForSlopeFaktor = rs.getBoolean(5);
int strecke_id = rs.getInt(7);
long longAthlet_id = (long) athlet_id;
Leistung leistung = new Leistung(strecke_id, longAthlet_id, bezeichnung, datum, geschwindigkeit);
leistung.setLeistungID(id);
leistung.setIsUsedForSlopeFaktor(selectedForSlopeFaktor);
alleLeistungen.add(leistung);
}
return alleLeistungen;
}
I marked the line after which the ResultSet is closed with a comment. Alle other methods, constructors, etc used in the above example are tested an working properly. Does anyone have a clue why calling the second method closes the ResultSet in the first method?

The problem is that the Statement can only maintain a single group of ResultSets per executed statement. Since you share the same Statement stmt for your two methods, in alleAbrufen the Statement executes another statement, which will break the reference to the prior ResultSet.
The best solution for this case is to create a Statement per statement execution. This is, every method should contain its unique Statement and related ResultSets.
public LinkedList<Athlet> alleAbrufen () throws SQLException {
LinkedList<Athlet> alleAthleten = new LinkedList<Athlet>();
String abrufenAthleten = "SELECT * FROM Athlet ORDER BY athlet_id";
//here
Statement stmtAlleAbrufen = con.createStatement();
ResultSet athleten_rs = stmtAlleAbrufen.executeQuery(abrufenAthleten);
while (athleten_rs.next()) {
long id = athleten_rs.getInt(1);
String name = athleten_rs.getString(2);
LinkedList<Leistung> alleLeistungen = alleAbrufen((int) (id)); //after this line the ResultSet gets closed
alleAthleten.add(new Athlet(id, name, alleLeistungen));
}
return alleAthleten;
}
public LinkedList<Leistung> alleAbrufen(int athlet_id) throws SQLException {
LinkedList<Leistung> alleLeistungen = new LinkedList<Leistung>();
//here again, but since you need to use parameters in your query
//use PreparedStatement instead
//note that I commented the current query
//String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id="+athlet_id;
//this is how a query with parameters look like
String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id=?";
//the connection prepares the statement
PreparedStatement pstmt = con.prepareStatement(selectLeistungen);
//then we pass the parameters
pstmt.setInt(1, athlet_id);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
long id = rs.getInt(1);
String bezeichnung = rs.getString(2);
String datum = rs.getString(3);
double geschwindigkeit = rs.getDouble(4);
boolean selectedForSlopeFaktor = rs.getBoolean(5);
int strecke_id = rs.getInt(7);
long longAthlet_id = (long) athlet_id;
Leistung leistung = new Leistung(strecke_id, longAthlet_id, bezeichnung, datum, geschwindigkeit);
leistung.setLeistungID(id);
leistung.setIsUsedForSlopeFaktor(selectedForSlopeFaktor);
alleLeistungen.add(leistung);
}
return alleLeistungen;
}
Don't forget to close the resources, Statement and ResultSet, after using them.

Your problem's answer comes from the 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.

Is your Statement a class variable and you are using the same for both the queries? Is yes, it's wrong. You can have only one ResultSet per Statement.
See the java docs.

Related

How to use Resultset?

I am using a mysql table, and now I need to compare a columns all values with a given String.
I want to check if all values of the result set matches with encryptedString.
Need to understand what result set does and how it works.
Here I have a method, Some variables, and 2 mysql queries.
final String secretKey = "!!!!";
String name = jText.getText();
String pass = jTextPass.getText();
String originalString = pass;
String encryptedString = AES.encrypt(originalString, secretKey) ;
String decryptedString = AES.decrypt(encryptedString, secretKey) ;
PreparedStatement PS;
ResultSet result;
String query1 = "SELECT `pass` FROM `Remember_Pass` WHERE `name` =?";
PreparedStatement ps;
String query;
query = "UPDATE `tutor profile` SET `pass`=? WHERE `name`=?";
try {
PS = MyConnection.getConnection().prepareStatement(query1);
PS.setString(1, name);
PS.setString(2, encryptedString);
rs = PS.executeQuery();
//while(result.next() ){
//I am not understanding what to do here.
ps = MyConnection.getConnection().prepareStatement(query);
ps.setString(1, encryptedString);
ps.setString(2, name);
ps.executeUpdate();
PassSuccess success = new PassSuccess();
success.setVisible(true);
success.pack();
success.setLocationRelativeTo(null);
this.dispose();
//}
} catch (SQLException ex) {
Logger.getLogger(ForgetPassT.class.getName()).log(Level.SEVERE, null, ex);
}
First tip: using try-with-resources closes statement and result set even on exception or return. This also reduces the number of variable names for them because of the smaller scopes. This return from the innermost block I utilized. For unique names one can use if-next instead of while-next. A fail-fast by not just logging the exception is indeed also better; you can exchange the checked exception with a runtime exception as below, so it easier on coding.
String query1 = "SELECT `pass` FROM `Remember_Pass` WHERE `name` = ?";
String query = "UPDATE `tutor profile` SET `pass`=? WHERE `name`= ?";
try (PreparedStatement selectPS = MyConnection.getConnection().prepareStatement(query1)) {}
selectPS.setString(1, name);
//selectPS.setString(2, encryptedString);
try (ResultSet rs = selectPS.executeQuery()) {}
if (result.next()){ // Assuming `name` is unique.
String pass = rs.getString(1);
try (PreparedStatement ps = MyConnection.getConnection().prepareStatement(query)) {
ps.setString(1, encryptedString);
ps.setString(2, name);
int updateCount = ps.executeUpdate();
if (updateCount == 1) {
PassSuccess success = new PassSuccess();
success.setVisible(true);
success.pack();
success.setLocationRelativeTo(null);
return success;
}
}
}
}
} catch (SQLException ex) {
Logger.getLogger(ForgetPassT.class.getName()).log(Level.SEVERE, null, ex);
throw new IllegalStateException(e);
} finally {
dispose();
}
the ResultSet object contains all the information about the query that you perform, it will contain all columns. In your code the result variable will return anything since there is no part in your code where is executed, to do this you have to...
Statement statement = MyConnection.getConnection().createStatement();
ResultSet result = statement.executeQuery("YOUR SELECT STATEMENT HERE");
while(result.next()){
String column1 = result.getString("columnName");
}
The result.next() method is a boolean method that says if the ResultSet object still have values of the table inside and it will continue until it reaches the last row that your SELECT statement retrives. Now if you want to match the value of some column with other variables you can do it inside the while(result.next()).
result.getString("columnName") will extract the value from columnName as a String.
If you want to save things in an ArrayList to save the data and then use this list as you want the code can be like...:
Statement statement = MyConnection.getConnection().createStatement();
ResultSet result = statement.executeQuery("YOUR SELECT STATEMENT HERE");
List<Object> data = new ArrayList();
while(result.next()){
data.add(result.getString("columnName"));
}
return data;
Obviously you have to change the Object with the type of things that you want to store in the List.
Or if you want to store the data in an array. As I said in my comment this won't be dinamic, but...:
Statement statement = MyConnection.getConnection().createStatement();
ResultSet result = statement.executeQuery("YOUR SELECT STATEMENT HERE");
String[] data = new String[NUMBER_OF_COLUMNS_IN_RESULTSET];
while(result.next()){
data[0] = result.getString("columnName1");
data[1] = result.getString("columnName2");
data[2] = result.getString("columnName3");
//And so on...
}
return data;
The other way is that if you are returning an entity you can set the values of the ResultSet directly in the POJO:
Statement statement = MyConnection.getConnection().createStatement();
ResultSet result = statement.executeQuery("YOUR SELECT STATEMENT HERE");
Entity entity = new Entity();
while(result.next()){
entity.setColumnName1(result.getString("columnName1"));
entity.setColumnName2(result.getString("columnName2"));
entity.setColumnName3(result.getString("columnName3"));
//And so on...
}
return entity;
There are so many ways to store the data, just ask yourself how do you want to receive the data in the other parts of you code.
Regards.

How to do Looping with ResultSet?

So, I want to loop this ResultSet in order to update the table one by one, but the method while(rsl.next()) can't help me do the looping. It's just work once, and then the others are skipped. Can someone help me fix this problem? Thanks in advance
try {
String url = "jdbc:mysql://localhost/minimarket";
String user = "root";
String pass = "";
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, pass);
Statement stmt = conn.createStatement();
ResultSet rsl = stmt.executeQuery("SELECT * FROM keranjang WHERE pemesan='"+login.userid+"'");
while (rsl.next()) {
String nb = rsl.getString("nama_barang");
String dtl = rsl.getString("detail");
String beratt = rsl.getString("berat");
String hrga = rsl.getString("harga");
String jmlh = rsl.getString("jumlah");
stmt.executeUpdate("UPDATE barang SET stok=stok+'"+jmlh+"' WHERE nama_barang='"+nb+"' AND detail='"+dtl+"' AND berat='"+beratt+"'");
stmt.executeUpdate("DELETE FROM keranjang WHERE pemesan ='"+login.userid+"' AND nama_barang='"+nb+"'");
}
conn.close();
} catch (Exception error) {
}
System.exit(0);
Problem:
if (rsl.next())
fix:
while (rsl.next())
Debug the app and check if the your connection to the database is valid.
When you execute an executeUpdate on your statement an int is returned and most importantly your result set object rs1 from your query gets closed and can't be accessed anymore since the Statement class only handles one query/result set. I haven't tested this myself but I am pretty sure this is the reason.
The solution is to have a separate Statement object for the update/delete so that the original ResultSet is not affected. Something like below
Statement stmt = conn.createStatement();
Statement updStmt = conn.createStatement();
ResultSet rsl = stmt.executeQuery("SELECT * FROM keranjang WHERE pemesan='"+login.userid+"'");
while (rsl.next()) {
String nb = rsl.getString("nama_barang");
String dtl = rsl.getString("detail");
String beratt = rsl.getString("berat");
String hrga = rsl.getString("harga");
String jmlh = rsl.getString("jumlah");
updStmt.executeUpdate("UPDATE barang SET stok=stok+'"+jmlh+"' WHERE nama_barang='"+nb+"' AND detail='"+dtl+"' AND berat='"+beratt+"'");
updStmt.executeUpdate("DELETE FROM keranjang WHERE pemesan ='"+login.userid+"' AND nama_barang='"+nb+"'");
}
If I've understood your problem correctly, there are two possible problems here:
the resultset is null - I assume that this cant be the case as if it was you'd get an exception in your while loop and nothing would be output
the second problem is that resultset.getString(i++) will get columns 1,2,3 and so on from each subsequent row
I think that the second point is probably your problem here.
Let us say you only had 1 row returned, as follows
Col 1, Col 2, Col3
A , B, C
Your code as it stands would only get A - it wouldn't get the rest of the columns.
I suggest you change your code as follows:
ResultSet resultset = ...;
ArrayList<String> arrayList = new ArrayList<String>();
while (resultset.next()) {
int i = 1;
while(i <= numberOfColumns) {
arrayList.add(resultset.getString(i++));
}
System.out.println(resultset.getString("Col 1"));
System.out.println(resultset.getString("Col 2"));
System.out.println(resultset.getString("Col 3"));
System.out.println(resultset.getString("Col n"));
}
To get the number of columns:
ResultSetMetaData metadata = resultset.getMetaData();
int numberOfColumns = metadata.getColumnCount();

Why do I get java.sql.SQLException: ResultSet not open. Operation 'next' not permitted. java derby database?

I'm getting this error:
java.sql.SQLException: ResultSet not open. Operation 'next' not
permitted. Verify that autocommit is off.
when I'm trying to create instances from a db.
Current code:
try
{
connection.setAutoCommit(false);
stmt = connection.createStatement();
results = stmt.executeQuery("SELECT * from animalTable");
int AnimalCat = -1;
System.out.print(connection.getAutoCommit());
//getting error on line below
while(results.next())
{
int ID = results.getInt(1);
int Age = results.getInt(2);
String Name = results.getString(3);
String AType = results.getString(4);
String Breed = results.getString(5);
AnimalCat = results.getInt(6);
int Adoption = results.getInt(7);
String Gender = results.getString(8);
String Description = results.getString(9);
if(Gender == "Male"){
gen = true;
}
animal = new Animal(Age, AType, gen, Breed, Description, Name);
animalList.add(animal);
if(AnimalCat != -1){
ResultSet resultCat = stmt.executeQuery("SELECT * from CategoryTable where ID = " + AnimalCat);
//without this line below i get a cursor error
resultCat.next();
System.out.println(resultCat.getInt(1) +"\n\n " + resultCat.getString(2));
String Category = resultCat.getString(2);
if(Category == "Lost"){
Date input = resultCat.getDate(3);
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
ResultSet personData = stmt.executeQuery("SELECT * from PersonTable where ID = " + resultCat.getInt(4));
Person person = new Person(personData.getString(2), personData.getString(3), personData.getString(4), personData.getString(5));
Category lost = new Lost(date, resultCat.getString(5), person);
animal.setAnimalCat(lost);
personList.add(person);
}
}
}
results.close();
stmt.close();
}
catch (SQLException sqlExcept)
{
sqlExcept.printStackTrace();
}
I have tried turning off auto commit like it says in the exception and also adding a finally block and closing the statement. From what I can see online that fixed others issues but no luck with mine.
I know the resultCat.next(); is behind the error somehow but I get an "Invalid cursor state - no current row" without it
You have a Statement, obtain a ResultSet from the statement, then obtain another ResultSet. This automatically closes the first ResultSet:
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.
So when you call next on the first ResultSet an exception is raised. The Javadoc also tells you what to change: Create a second statement and use that to obtain the second ResultSet.

JDBC Sql exhausted ResultSet [duplicate]

I'm having a really bad time with a ResultSet, which is closed within a while-Loop for iterating this ResultSet. I have know the exact line in which the ResultSet is closed, but i have no idea why.
public LinkedList<Athlet> alleAbrufen () throws SQLException {
LinkedList<Athlet> alleAthleten = new LinkedList<Athlet>();
String abrufenAthleten = "SELECT * FROM Athlet ORDER BY athlet_id";
ResultSet athleten_rs = stmt.executeQuery(abrufenAthleten);
while (athleten_rs.next()) {
long id = athleten_rs.getInt(1);
String name = athleten_rs.getString(2);
LinkedList<Leistung> alleLeistungen = alleAbrufen((int) (id)); //after this line the ResultSet gets closed
alleAthleten.add(new Athlet(id, name, alleLeistungen));
}
return alleAthleten;
}
public LinkedList<Leistung> alleAbrufen(int athlet_id) throws SQLException {
LinkedList<Leistung> alleLeistungen = new LinkedList<Leistung>();
String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id="+athlet_id;
ResultSet rs = stmt.executeQuery(selectLeistungen);
while (rs.next()) {
long id = rs.getInt(1);
String bezeichnung = rs.getString(2);
String datum = rs.getString(3);
double geschwindigkeit = rs.getDouble(4);
boolean selectedForSlopeFaktor = rs.getBoolean(5);
int strecke_id = rs.getInt(7);
long longAthlet_id = (long) athlet_id;
Leistung leistung = new Leistung(strecke_id, longAthlet_id, bezeichnung, datum, geschwindigkeit);
leistung.setLeistungID(id);
leistung.setIsUsedForSlopeFaktor(selectedForSlopeFaktor);
alleLeistungen.add(leistung);
}
return alleLeistungen;
}
I marked the line after which the ResultSet is closed with a comment. Alle other methods, constructors, etc used in the above example are tested an working properly. Does anyone have a clue why calling the second method closes the ResultSet in the first method?
The problem is that the Statement can only maintain a single group of ResultSets per executed statement. Since you share the same Statement stmt for your two methods, in alleAbrufen the Statement executes another statement, which will break the reference to the prior ResultSet.
The best solution for this case is to create a Statement per statement execution. This is, every method should contain its unique Statement and related ResultSets.
public LinkedList<Athlet> alleAbrufen () throws SQLException {
LinkedList<Athlet> alleAthleten = new LinkedList<Athlet>();
String abrufenAthleten = "SELECT * FROM Athlet ORDER BY athlet_id";
//here
Statement stmtAlleAbrufen = con.createStatement();
ResultSet athleten_rs = stmtAlleAbrufen.executeQuery(abrufenAthleten);
while (athleten_rs.next()) {
long id = athleten_rs.getInt(1);
String name = athleten_rs.getString(2);
LinkedList<Leistung> alleLeistungen = alleAbrufen((int) (id)); //after this line the ResultSet gets closed
alleAthleten.add(new Athlet(id, name, alleLeistungen));
}
return alleAthleten;
}
public LinkedList<Leistung> alleAbrufen(int athlet_id) throws SQLException {
LinkedList<Leistung> alleLeistungen = new LinkedList<Leistung>();
//here again, but since you need to use parameters in your query
//use PreparedStatement instead
//note that I commented the current query
//String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id="+athlet_id;
//this is how a query with parameters look like
String selectLeistungen = "SELECT * FROM Leistung WHERE athlet_id=?";
//the connection prepares the statement
PreparedStatement pstmt = con.prepareStatement(selectLeistungen);
//then we pass the parameters
pstmt.setInt(1, athlet_id);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
long id = rs.getInt(1);
String bezeichnung = rs.getString(2);
String datum = rs.getString(3);
double geschwindigkeit = rs.getDouble(4);
boolean selectedForSlopeFaktor = rs.getBoolean(5);
int strecke_id = rs.getInt(7);
long longAthlet_id = (long) athlet_id;
Leistung leistung = new Leistung(strecke_id, longAthlet_id, bezeichnung, datum, geschwindigkeit);
leistung.setLeistungID(id);
leistung.setIsUsedForSlopeFaktor(selectedForSlopeFaktor);
alleLeistungen.add(leistung);
}
return alleLeistungen;
}
Don't forget to close the resources, Statement and ResultSet, after using them.
Your problem's answer comes from the 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.
Is your Statement a class variable and you are using the same for both the queries? Is yes, it's wrong. You can have only one ResultSet per Statement.
See the java docs.

incorrect value of timestampdiff being passed in java result set variable

I have a simple requirement of getting timestampdifF in mysql database and use the resultset value in java code to check a condition if the timestampdiff is greater than 15 minutes, if yes do some update in DB or else skip and continue the next flow.
However, I am not getting the correct value when I pass the result set value in Java. The same query returns the correct value when executed on the database directly. Below is a snippet of my code:
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
String Diff = null;
try {
conn = Daofactory.getconnection();
String sql = "select TIMESTAMPDIFF(MINUTE,max(start_tstamp),NOW()) as timediff from app.process_log where status = 'P'";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while(rs.next()) {
log.info("Inside while loop");
Diff = rs.getString(1);
}
if(Diff.equalsIgnoreCase("15")) {
String sql1 = "update statement here";
stmt = conn.prepareStatement(sql1);
int i = stmt.executeUpdate();
}
When I execute the query on DB directly it returns the correct value in minutes; however, when I run the program the timeDiff is always 0. How can I fix this?

Categories

Resources