private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ConnectionDTB cdtb = new ConnectionDTB();
ResultSet rs = cdtb.retrieveData("select svcode from listSV");
if(!rs.isBeforeFirst()){
System.out.println("System is null");
//add
cdtb.close();
}
else{
while(rs.next()){
if(Integer.parseInt(jTextField1.getText()) == rs.getInt("svcode")){
System.out.println("ERROR");
cdtb.close();
break;
}
else{
if(rs.isLast()){
//add
cdtb.close();
}else{
cdtb.close();
}
}
My error is
Apr 25, 2015 2:21:29 AM GUI.Them1 jButton1ActionPerformed
SEVERE: null
java.sql.SQLException: Operation not allowed after ResultSet closed
What did I do wrong?
It looks like you are closing the database connection inside your loop, before you are done with the result set.
You can't close the database connection if you are still using statements or resultsets associated with the database connection. (Well, you can do it, but closing the connection will also close the resultset, and you get the kind of behavior you observe.)
The normative pattern is to use try/catch/finally blocks, and to close the resultset(s), statements(s) and connection in the finally block(s).
For example:
ConnectionDTB cdtb = null;
ResultSet rs = null;
try {
cdtb = new ConnectionDTB();
rs = cdtb.retrieveData("select svcode from listSV");
while(rs.next()){
// whatever processing you need to do on each row, but
// do NOT close the result set here
// do NOT close the database connection here!
}
} catch (SQLException ex) {
// anything you want to do if an exception is thrown
} finally {
if (rs != null) {
try { rs.close(); } catch (SQLException e) { /*ignore*/ }
}
if (cdtb != null) {
try { cdtb.close(); } catch (SQLException e) { /*ignore*/ }
}
}
That finally block could be simplified, removing the unnecessary try/catch. This would be fine too:
} finally {
if (rs != null) {
rs.close();
}
if (cdtb != null) {
cdtb.close();
}
}
The important thing here is to do the closing in the "finally" block, so that's going to be run even if an exception occurs. And with this pattern, there is one "close" of the database connection, it's not multiple calls scattered through your code.
Some other notes:
It looks as if your code means to "add" a row if one doesn't already exist. This is a lot of overhead, pulling back every value from the database and inspecting it.
It would be much more efficient to ask the database if such a row exists. To ask the database whether a row like that exists, use a statement like this:
SELECT svcode FROM listSV WHERE svcode = ?
Prepare the statement, bind a value to the placeholder (the value you are looking for), and execute the statement, and check if a row is returned or not.
If you are performing this check to see whether a row needs to be added to the listSV table, you could actually use a single INSERT ... SELECT statement to conditionally insert a row.
Although I don't think its actually shown from the information provided, I think that you are closing the result set (in this case 'rs') and then attempting to run an operation again.
If I had to guess as well, I'd say take out the rs.close because it is closing the result set prematurely. Maybe replace with a continue if you wanted to keep reading from the same set?
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ConnectionDTB cdtb = new ConnectionDTB();
ResultSet rs = cdtb.retrieveData("select svcode from listSV");
if(!rs.isBeforeFirst()){
System.out.println("System is null");
//add
cdtb.close();
rs.close();
}
else{
while(rs.next()){
if(Integer.parseInt(jTextField1.getText()) == rs.getInt("svcode")){
System.out.println("ERROR");
cdtb.close();
rs.close();
break;
}
else{
if(rs.isLast()){
//add
cdtb.close();
rs.close();
}
}
is this right?
by the way could u tell me AfterLast meaning?
Related
I have a Java application with many code snippets like the example below. Very simple querying of an Oracle database. Valid data is returned and parsed, then the close() functions are called.
ResultSet rs = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM example");
while (rs.next())
{
// do stuff
}
rs.close();
stmt.close();
System.out.println("test1");
}
catch (Exception e)
{
System.out.println("error1");
}
I started encountering a "maximum cursors exceeded" error. I checked my methods to determine whether ResultSets are not being closed. The catch clause was never triggered, and "test1" was printed every single time. Which means the rs.close() and stmt.close() lines are NOT being skipped. Yet the ResultSets are not actually being closed.
I added a finally clause and it cleared up the issue.
finally
{
if (rs != null)
{
try
{
rs.close();
System.out.println("test2");
}
catch (Exception e)
{
System.out.println("error2");
}
}
if (stmt != null)
{
try
{
stmt.close();
System.out.println("test3");
}
catch (Exception e)
{
System.out.println("error3");
}
}
}
OUTPUT:
test1
test2
test3
My question is, why do rs.close() and stmt.close() need to be called twice? The calls in the try clause appear to do nothing. Yet I call them again in the finally clause, and they are successful. How is this possible?
Use try-with-resources (Java 7+):
try (Statement stmt = conn.createStatement()) {
try (ResultSet rs = stmt.executeQuery("SELECT * FROM example")) {
while (rs.next()) {
// do stuff
}
System.out.println("test1");
}
} catch (Exception e) {
System.out.println("error1");
}
No, no need to call twice
No, there is no need in JDBC to be calling close twice. I suspect something else is going on.
We cannot tell for sure what is going on in your code with certainty. We cannot know if your supposedly second call actually fixed the problem. The documentation for Statement::close, for example, says:
Calling the method close on a Statement object that is already closed has no effect.
try-with-resources
As the Answer by Andreas suggests, you should be using a try-with-resources.
See:
Java 7 tech note on try-with-resources.
Oracle Tutorial.
Java 9 enhancement to try-with-resources, using previously-created variable within Try-With-Resource Statement.
Use try-with-resources for JDBC and also for any resource implementing AutoCloseable.
You can put one or more resources in your try( … ). Separate with semi-colons, the last semi-colon being optional. Java will take of tracking the resources, each being closed in the reverse order of being opened. If an exception occurs in the middle, Java knows not to try closing the null resource objects. This significantly simplifies your coding.
Whenever I try and run this code I get: "java.sql.SQLException: Operation not allowed after ResultSet closed". It works without closing the connection but i'm curious as to why I get this error and what would be the correct way to close the connection, Here is the code:
public ResultSet UpdateTable(){
Connection con = connect();
ResultSet resultset;
Statement s = null;
resultset = null;
try{
s = con.createStatement();
resultset = s.executeQuery("select * from customera");
return resultset;
}
catch(SQLException e){
System.out.println(e.getMessage());
//con.close();
}
finally{
try{
s.close();
resultset.close();
con.close();
}
catch(SQLException e){
System.out.println(e.getMessage());
}
}
return null;
}
}
You would rather check whether they have any reference or not, then close them.
finally {
if (resultset != null) {
resultset.close();
}
if (s != null) {
s.close();
}
if (con != null) {
con.close();
}
}
I suspect, issue with
return resultset;
Since, you are closing the Connection and Statement before returning the ResultSet, so ResultSet might not be available. You must be aware finally block will execute before returning the value. That is also why, your code is working when you left your Connection open.
So, instead you should store the result into some data structure and return.
Your error is likely not coming from the code you show. Instead, it is being generated by other code, as a result of you closing your ResultSet and Statement before that other code uses it. (Closing the Statement also closes its ResultSet, according to the documentation.)
You can either call whatever code you need to finish using the ResultSet in this method, or you can just return the ResultSet and have it be the calling code's responsibility to close it. What you decide may depend on your other code, but I'd prefer making it be the calling code's responsibility (since it's specifically getting a ResultSet from this method, it should know it has to close it.)
As a side note, you should better differentiate your exception messages, so you can tell where they are coming from.
Here is my problem, I need to select data, but the data may be a lot so need to select the total results as well, so i need to call PreparedStatement twice for the same fields. I don't want to repeatedly write the same code twice, so I want put PreparedStatement into a different method. See ex:
public Order getOrders(){
Connection myCon = null;
PreparedStatement preparedStmt=null;
try{
myCon =getUnusedConnection();
String sql="select * from order where name=? ....... limit 0,3";
preparedStmt=myCon.prepareStatement(sql);
getOrderPreparedStatement(name,....);
ResultSet results=preparedStmt.executeQuery();
int rowCount=0;
while(results.next()){
......
rowCount++;
}
if(rowCount==3){
String sql2="select count(*) from Order where name=?....";
preparedStmt=myCon.prepareStatement(sql);
getOrderPreparedStatement(name,....);
ResultSet results2=preparedStmt.executeQuery();
if(results2){
int totalRow=....;
}
}
}
catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally {
closeStatement(preparedStmt);
releaseConnection(myCon);
}
return null;
}
public void getOrderPreparedStatement(PreparedStatement preparedStmt, String name....)
{
try{
preparedStmt.setString(name);
... a lot of set field here....
}
catch (SQLException ex) {
while (ex != null) {
System.out.println ("SQL Exception: " +
ex.getMessage ());
ex = ex.getNextException ();
}
}catch (java.lang.Exception e) {
System.out.println("***ERROR-->" + e.toString());
}
finally {
closeStatement(preparedStmt); // do i need to close Statement in finally here
}
}
Is it a good practice to put Connection in 1 method & PreparedStatement in a seperated method. If it is ok to do that then "do i need to closeStatement in finally in getOrderPreparedStatement method?"
Or can u suggest a better solution?
Although it is definitely a good idea to move the code for repeated tasks into a method, you need to be very careful when deciding how much code to reuse.
Specifically, in your example you should not attempt to close the statement in the finally clause, because the statement that you prepare would be unusable outside the getOrderPreparedStatement.
One thing that you could do differently is dropping the exception-handling code from the method. This would keep the logic inside the method cleaner, so your readers would have easier time understanding your intentions. This would also reduce code duplication, because currently the code inside the catch (SQLException ex) block is identical.
I was working on a servlet that will generate a unique code and update that in a mySQL database.
Now, in that, I want to catch any exception thrown in case that unique code already exists in the mySQL table and generate a new code and try updating the database. The problem is I want to do this WITHIN the for loop itself. The code is as follows:
try
{
connection = datasource.getConnection();
SQLUpdate = "INSERT INTO Voucher_dump VALUES( '"+unique_code+"','08-10-2011 04:48:48','0')";
PreparedStatement ps1 = connection.prepareStatement(SQLUpdate);
ps1.executeUpdate();
ResultSet r = ps1.getResultSet(); // this is where I'm checking if it's a duplicate
if(r==null)
out.println("This is a duplicate");
else out.println("Updated");
trial12= "08-10-2011 04:48:480.03999855056924717a";
SQLUpdate = "INSERT INTO Voucher_dump VALUES( '"+trial12+"','08-10-2011 04:48:48','0')";
ps1 = connection.prepareStatement(SQLUpdate);
ps1.executeUpdate();
r = ps1.getResultSet();
if(r==null)
out.println("This is a duplicate");
else out.println("Updated");
}
catch (SQLException sqle)
{
sqle.printStackTrace();
}
I don't want to wait till the end of the entire loop to catch the SQLException (I have already defined this key in mySQL as primary). The moment, the result comes back as a duplicate entry, I want to re-generate this key and attempt the update again.My output for this particular code is coming blank on my output page (all other parameters are showing correctly). Neither is "This is a duplicate" displayed nor is "Updated". Maybe, ResultSet is not the best way to do it. Could you guys give me some advice on what would be the best way forward ?
Some advice in no particular order:
Close the connection in a finally block.
Close statements individually if you'll be creating many of them before closing the connection. ("Many" is defined by your DBAs.)
Format your code.
Don't use stdout and/or stderr from real code. Pick a logging framework.
Consider using some helper classes to simplify (and correct) your database access, like Spring's JdbcTemplate.
Make sure to include relevant context when you post example code.
Due to #6, I don't know what out is, but I suspect the reason you're not seeing anything is that you're inserting a duplicate value with the first statement, which will cause a SQLException from that line, not at getResultSet(), where you seem to expect it. Since the error is written to stdout, it'll show up in your server logs somewhere, but nothing will be written to out. I'm not sure why you think getResultSet() will return null or not null depending on whether there was a constraint violation. Take a look at the javadoc for that method.
Update: 7. As BalusC points out, never, ever concatenate a string directly into a JDBC Statment. Use PreparedStatment's placeholders and set* methods. For info on SQL injection, see Wikipedia and XKCD.
How about this code?
try {
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url + dbName);
System.out.println("Connected to the database");
int i = 1; //get the unique code
boolean isInserted = false;
while (!isInserted) {
try {
PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO test values (?)");
preparedStatement.setInt(1, i);
preparedStatement.executeUpdate();
isInserted = true;
} catch (com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException e) { //Catch the particular exception which throws error on unique constraint. This may depend on Java/MySQL your version
i++; //get the next unique code
}
}
System.out.println("Disconnected from database");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e) {
}
}
I'm trying to delete an event from my table. However I can't seem to get it to work.
My SQL statement is:
public void deleteEvent(String eventName){
String query = "DELETE FROM `Event` WHERE `eventName` ='"+eventName+"' LIMIT 1";
db.update(query);
System.out.println (query);
}
Using MySQL db
Try using the following :
String query = "DELETE FROM `Event` WHERE `eventName` ='"+eventName+"' LIMIT 1";
try {
Connection con = getConnection();
Statement s = con.createStatement();
s.execute(query);
} catch (Exception ex) {
ex.printStackTrace();
}
You have to code your getConnection() method to return a valid Database Connection.
I would suggest using Statement.executeUpdate method, since it returns an integer. So after performing this delete query you will also have information if you really deleted any records (in this case you would expect this method to return 1, since you are using LIMIT=1). I would also suggest closing Statement as soon as you don't need it, here is skeleton implementation:
private void performDelete(Connection conn, String deleteQuery, int expectedResult) throws SQLException {
Statement stmt = conn.createStatement();
int result = -1;
try {
result = stmt.executeUpdate(deleteQuery);
if(result != expectedResult) {
//Here you can check the result. Perhaps you don't need this part
throw new IllegalStateException("Develete query did not return expected value");
}
} catch(SQLException e) {
//Good practice if you use loggers - log it here and rethrow upper.
//Or perhaps you don't need to bother in upper layer if the operation
//was successful or not - in such case, just log it and thats it.
throw e;
} finally {
//This should be always used in conjunction with ReultSets.
//It is not 100% necessary here, but it will not hurt
stmt.close();
}
}