java exception: Operation not allowed after ResultSet closed - java

i have the following exception:
here is the relevant code parts:
Server.Proxy.update_allLogOut: (line 65 is the while bracket)
public void update_allLogOut ()
{
try
{
ResultSet rs;
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM sysuser WHERE login=1");
while(rs.next())
{
stmt.executeUpdate("UPDATE sysuser SET login=0");
}
rs.close();
} catch (SQLException e) {e.printStackTrace();}
}
Server.Server.:
public Server(int port)
{
super(port);
func.update_allLogOut();
}
main:
Server sv = new Server(5555);
i must point out that 99% of times it runs with no exceptions.. but several times i get this exception that i cant figure out why it happens. any ideas? it is clear that something is done wrong yet all similar topics here have not given the answer in this case...

You are using stmt to both iterate over the results of SELECT and to UPDATE inside the loop. This doesn't work since the moment you execute the UPDATE, the result set associated with the SELECT gets closed.
To fix, use two separate Statement objects.

I'm not sure, that this block:
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM sysuser WHERE login=1");
while(rs.next())
{
stmt.executeUpdate("UPDATE sysuser SET login=0");
}
rs.close();
is a good idea.
Why not just execute simple query: UPDATE sysuser SET login=0 WHERE login=1?
Furthermore, using same stmt inside while loop - it is rough mistake.

Related

Select * From java with preparedStatement [duplicate]

This question already has answers here:
Java MYSQL Prepared Statement Error: Check syntax to use near '?' at line 1
(2 answers)
Closed 1 year ago.
I faced this problem today with my select SQL. This method is supposed to show data from database in tex tfields. I changed it from statement to preparedStatement, but I faced a problem.
public Entreprise loadDataModify(String id) {
Entreprise e = new Entreprise();
PreparedStatement stmt;
try {
String sql = "SELECT * FROM user WHERE mail=?";
stmt = cnx.prepareStatement(sql);
stmt.setString(1, id);
ResultSet rst = stmt.executeQuery(sql);
while (rst.next()) {
stmt.setString(2, e.getNom());
stmt.setString(3, e.getEmail());
stmt.setString(4, e.getTel());
stmt.setString(5, e.getOffre());
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
return e;
}
It shows i have problem with syntax and the output is " nu
You're calling the wrong method. Unlike Statement, when you're using a PreperedStatement you should first set the values for the parameters, and after you can call on that instance executeQuery() method.
Also, it's a best practice to use try-with-resources, because a Statement or PreparedStament object is a Resource (a resource is a class that implements AutoCloseable interface) and you have to close it. Using try-with-resources, it's done automatically.
The ResultSet instance is also a resource, but it's closed when the statement object is closed, so you don't have to close it explicitly.
So, the best way to solve your problem will be:
String selectAllByMail = "SELECT * FROM user WHERE mail=?";
try (PreparedStatement prpStatement = connection.prepareStatement(selectAllByMail)) {
// use prpStatement
prpStatement.setString(1, id);
ResultSet resultSet = prpStatement.executeQuery();
while (resultSet.next()) {
// process resultSet
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
You are not filling your Enterprise object. And you are not using executeQuery() function correctly. As seen below, the parameter inside the brackets has been removed. PreparedStatements first of all need the values of the parameters (your ? in the query) and then the formed query has to be executed. If you give a String parameter to executeQuery() then the query in the brackets will be executed.
And the part where Enterprise is being filled could be seen below.
This would be the correct way:
public Entreprise loadDataModify(String id) {
Entreprise e = new Entreprise();
PreparedStatement stmt;
try {
String sql = "SELECT * FROM user WHERE mail=?";
stmt = cnx.prepareStatement(sql);
stmt.setString(1, id);
ResultSet rst = stmt.executeQuery();
while (rst.next())
{
// rst keeps the data, so you have to traverse it and get the data from it in this way.
e.setNom( rst.getString("HERE EITHER THE COLUMN NAME OR INDEX"));
e.setEmail( rst.getString("HERE EITHER THE COLUMN NAME OR INDEX"));
e.setTel( rst.getString("HERE EITHER THE COLUMN NAME OR INDEX"));
e.setOffre( rst.getString("HERE EITHER THE COLUMN NAME OR INDEX"));
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
return e;
}
Your call to executeQuery() should not be passing the query string. Use this version:
String sql = "SELECT * FROM user WHERE mail=?";
stmt = cnx.prepareStatement(sql);
stmt.setString(1, id);
ResultSet rst = stmt.executeQuery();
while (rst.next()) {
// process result set
}
Your current code is actually calling some overloaded Statement#executeQuery() method, which is not the version of the method which you want to be calling.

SQL select column with conditions JAVA

I tried to get specific value where the column of names in my database contains "jansen",but when i run my code it shows error like this
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'jansen' in 'where clause'
here is my code
try {
Statement stmt=MyConnection.getConnection().createStatement();
ResultSet rs=stmt.executeQuery("select * from emp where name = jansen");
while(rs.next())
System.out.println(rs.getInt(1)+" "+rs.getString(2)+" "+rs.getString(3));
}catch (Exception e){
System.out.println(e);
}
[and here is my database in Sqlyog]
You should put quotes around string values in your SQL statement.
"select * from emp where name = 'jansen'"
Another issue you may run into later, is that your resources (e.g. connection, statement, ...) aren't cleaned up after you've used them. You should actually call the close() function after using it. You would then have to put that code inside a finally block, and again catch it to prevent having the close function itself throwing exceptions. Because it would be messy and bloated, there's a better solution to clean things up:
Create your statement between the braces of your try, and it will close it cleanly for you. (It's called a try-with-resources statement)
try (Statement stmt = MyConnection.getConnection().createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
...
}
} catch (SQLException e) {
System.out.println(e);
}
You can read more about executing SQL statements in java, in the official tutorial.
You should use a PreparedStatement instead of Statement in this way:
PreparedStatement statement = MyConnection.getConnection().prepareStatement("select * from emp where name = :empId");
statement.setString(empId, "jansen");
ResultSet rs = statement.executeQuery();
Then "jansen" would be replaced by String variable with dynamic name.

Get the results after the it is closed

I am using the sqlite driver with java. As you know the typical order is
Create Statement
Execute Statement
Get ResultSet
Process Results
close ResultSet
close statement
The problem is that all of above is in one method and I want the caller to get the results and process it. However since the results are returned at the end of the method then by then the statement and the result set is closed.
The only work around I can think of is to have the RS and the Stmnt be a class variable and have the caller close them but this will pose problem if it is multi threaded env.
What is the recommended way to achieve what I want?
Thanks
public ResultSet runQuery(String sql) {
try {
st = conn.createStatement();
rs = st.executeQuery(sql);
rs.close();
st.close()
} catch (SQLException ex) {
Logger.getLogger(DatabaseHelper.class.getName()).log(Level.SEVERE, null, ex);
}
return rs
}
From another file
private void displayListOfEmployee(){
String sql = "Select * from employee";
ResultSet rs = DB.getInstance().runQuery(sql);
while(rs.next()!=null){
System.out.println(.....); // display value of column
}
}
You can add a Consumer<ResultSet> parameter to the method:
public void query(String query, Consumer<ResultSet> consumer) {
// Create Statement
try (Statement stmt = ...) {
// Execute Statement
ResultSet rs = ...
consumer.accept(rs);
}
}
With this the caller can extract its data from the result set and you can guarantee that resources are closed.
A variation would be to use a Function parameter and compute a return value:
public <T> T query(String query, Function<ResultSet,T> function) {
// Create Statement
try (Statement stmt = ...) {
// Execute Statement
ResultSet rs = ...
return function.apply(rs);
}
}
Since Consumer.accept and Function.apply do not allow to throw checked exceptions you may want to define similar functional interfaces which allow checked exceptions and use it in that method.
UPDATE:
Your example would translate to:
private void displayListOfEmployee(){
String sql = "Select * from employee";
DB.getInstance().runQuery(sql, rs -> {
while (rs.next())
System.out.println(.....); // display value of column
});
}
A possible solution would be to use a CachedRowSet, which is populated from a ResultSet but can outlive the associated Statement/Connection the ResultSet was produced by.
Note this will read the entire ResultSet into memory.

Is putting a string literal in executeQuery prone to an SQL injection in JDBC?

I've been looking around and can't seem to find a solid answer to this. I was wondering if putting a string literal in executeQuery() is still prone to SQL injection.
So lets say I have this code:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
Is this prone to a SQL injection?
Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?
For example:
public void execMethod(String uid) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/","root","password");
Statement stmt = conn.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from users where uid = "+uid);
// execute some other code
res.close();
}
public static void main(String[] args) {
try {
execMethod("123");
execMethod("456");
} catch(Exception ex) {
ex.printStackTrace();
}
}
Is this the standard or correct way of using SQL exceptions? I've never really worked with SQL and especially not Java and SQL. The tutorials I've read seem to only lay it out one way, so I'm pretty unsure of myself.
Is this prone to a SQL injection?"
Yes, you have no control over what uid might actually contain.
See Using Prepared Statements for more details
Another question is, is just making the method that uses this code only throw an SQLException, and then trying and catching in main acceptable?"
Yes, but you should at least wrap the contends of execMethod in try-finally to ensure that you are closing the resources you open (or use a try-with-resources for Java 7)
public void execMethod(String uid) throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/", "root", "password")) {
try (PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")) {
stmt.setString(1, uid);
try (ResultSet res = stmt.executeQuery()) {
// Process ressult set
}
}
}
}
See The try-with-resources Statement for more details
But, I would only catch the SQLException for EACH call, not batch them together, as you won't know what failed and what succeeded
try {
execMethod("123");
try {
execMethod("456");
} catch (Exception ex) {
// Maybe undo 123
System.out.println("Failed 456");
ex.printStackTrace();
}
} catch (Exception ex) {
System.out.println("Failed 123");
ex.printStackTrace();
}
(assuming that 456 is dependent on the success of 123)
Short answer : yes.
You do not appear to be doing any kind of input validation so there isn't anything stopping uid from being something like "105 or 1=1"
You should probably use PreparedStatements tutorial here
PreparedStatement stmt = conn.prepareStatement("SELECT * from users where uid = ?")
stmt.setString(1, uid);
..same as before
Also you don't close the statement or the connection which should be done in a finally block incase an exception is thrown
Yes. If uid can be entered by a user (it's not a String literal). I suggest you use a PreparedStatement, and a try-with-resources like
final String sql = "SELECT * from users where uid = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, uid);
try (ResultSet res = ps.executeQuery()) {
while (res.next()) {
// ...
}
}
}
The PreparedStatement (with bind variable) has at least these advantages
It can use the Statement cache on the server
It is not prone to SQL Injection

Proper way to return a ResultSet

I'm new to java but I'm picking it up pretty quickly. One thing that I keep running into is I end up having one function that is full of queries and just code in general and I would like to break it down into separate functions. Take this for example:
public ResultSet getApples (){
ResultSet rs;
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
rs = stmt.executeQuery();
} catch (SQLException e){
e.printStackTrace();
}
return rs;
}
Ideally this would be what I want to do, have all of try's and catches within one function, but this gives me the error: Local variable may not have been initilized
I do realize I could do this:
public function start(){
try{
ResultSet apples = getApples();
catch (SQLException e){
e.printStackTrace();
}
}
public ResultSet getApples () throws SQLException {
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
return stmt.executeQuery();
}
But I would really rather have the exceptions handled within the function as well as it return a result.
EDIT
Alright so kinda a modififed answer to whats being provided. My whole goal on this question was to make the main functions of my script as clean as possible. Even the extra if ( _resultSet != null ) was something that I didn't really like. That being said I am pretty happy with this result:
public ResultSet getApples (){
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
return stmt.executeQuery();
} catch (SQLException e){
System.out.println("************************");
System.out.println("Class.getApples null");
System.out.println(e.getMessage());
return null;
}
}
Everything is handled within the getApples function and when _resultSet.next() is called I get a NullPointerException and the prints in the getApples exception so I am able to find the error and debug quickly.
Initialize rs to null first.
public ResultSet getApples (){
ResultSet rs = null;
try{
PreparedStatement stmt = con.prepareStatement("SELECT * FROM fruit WHERE type='apples'");
rs = stmt.executeQuery();
} catch (SQLException e){
e.printStackTrace();
}
return rs;
}
You can declare your RS like this
ResultSet rs = null;
but where you call your function:
ResultSet apples = getApples ()
you have to check:
if(apples == null)
{
//do something, because your query did not work.
}
Because you are not setting ResultSet rs to anything initial value. and at the end you are returning it.
What if any exception occurs and rs value does not have value set in it. In order to solve you need to assign null value to rs when you declare.
The biggest problem that I see with your first example (other than not initializing rs) is that you don't properly handle cleanup. You should have a finally block that closes stmt.
One very good way to make sure that all of this happens is to use Spring's JDBCTemplate (more documentation here). This handles all of the connection management details for you; you simply write your SQL and code to process the ResultSet. Better, it lets you use Spring's declarative transaction management.
You can use CachedRowSet. For detailed answer you can look at my answer here

Categories