In this code, would the connection be closed?
Connection con = DriverManager.getConnection(dbUrl, user, pass);
try (Statement st = con.createStatement()) {
ResultSet rs = st.executeQuery(query);
}
Something in my code is unexpectedly closing the connection, I'd like to make sure it isn't this.
No, invoking close on Statement will not close Connection. This would prevent us from creating next statement on already opened connection which means we would have to create new Connection (which can be expensive operation) for each Statement.
You can test it very easily. Just try to create another statement after previous one was closed.
Connection con = DriverManager.getConnection(dbUrl,user,pass);
try (Statement st = con.createStatement()) {
ResultSet rs = st.executeQuery(sqlQuery1);
simplePrint(rs);
} catch (SQLException e) {
e.printStackTrace();
}//here `st` will be closed automatically by try-with-resources
try (Statement st = con.createStatement()) {//lets try to create next statement
ResultSet rs = st.executeQuery(sqlQuery2);
simplePrint(rs);
} catch (SQLException e) {
e.printStackTrace();
}
simplePrint method may look like this:
public static void simplePrint(ResultSet rs) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
while (rs.next()) {
for (int i = 1; i <= meta.getColumnCount(); i++) {
System.out.print(rs.getObject(i)+"\t");
}
System.out.println();
}
}
Related
Is it necessary to close ResultSet and PreparedStatement within one db.getConnection()? For the example below:
Connection conn = db.getConnection();
PreparedStatement pstmt = conn.prepareStatement(firstsql);
ResultSet r = pstmt.executeQuery();
// do something with the ResultSet
r.close();
pstmt.close(); // do I need close the r and pstmt here?
PreparedStatement pstmt = conn.prepareStatement(secondsql);
ResultSet r = pstmt.executeQuery();
// do something with the ResultSet again
r.close();
pstmt.close();
conn.close();
return null;
Are the codes of line 5 and line 6 necessary?
Strictly speaking, it is not necessary because you can have multiple prepared statements opened at the same time. What is necessary is to close every opened resource if it is not going to be utilised later.
Looking at your code, it doesn't ensure that the statement are, in fact, closed.
To ensure this, every close operation must be done inside a finally block: this way, it will executed whether the operation succeded or not.
Sample code:
PreparedStatement pstmt = null;
ResultSet r = null;
try {
pstmt = conn.prepareStatement(firstsql);
r = pstmt.executeQuery();
// do something with the ResultSet
} finally {
if (r != null) {
try {
r.close();
} catch (SQLException e) {
//log error
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
//log error
}
}
}
//and do it again
This code can be greatly simplified if you are using Java 7 with the try-with-resources statement:
try (PreparedStatement pstmt = conn.prepareStatement(firstsql);
ResultSet r = pstmt.executeQuery();) {
// do something with the ResultSet
}
No. You can have multiple statements open at the same time. But you must close them eventually.
The code you've posted doesn't compile, and if it did it would have a resource leak, but that's a different issue from the question in your title.
Why are database connections often closed at two positions, once directly after use, and secondly additionally in a finally-block using a check for null in order to prevent them to be closed twice. Doesn't it suffice to use the finally block? The finally-block is to be executed in every case.
Here is an official example of Apache-Tomcat JNDI Datasource HOW-TO. They point out there that a connection MUST be closed under every circumstance. I wonder why it is not sufficient to use the finally-block as the close-commands within the end of the main try {}-block seem to be redundent.
Connection conn = null;
Statement stmt = null; // Or PreparedStatement if needed
ResultSet rs = null;
try
{
conn = ... get connection from connection pool ...
stmt = conn.createStatement("select ...");
rs = stmt.executeQuery();
... iterate through the result set ...
rs.close ();
rs = null;
stmt.close ();
stmt = null;
conn.close (); // Return to connection pool
conn = null; // Make sure we don't close it twice
}
catch (SQLException e)
{
... deal with errors ...
}
finally
{
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (rs != null)
{
try
{
rs.close ();
}
catch (SQLException ignore)
{
}
rs = null;
}
if (stmt != null)
{
try
{
stmt.close ();
}
catch (SQLException ignore)
{
}
stmt = null;
}
if (conn != null)
{
try
{
conn.close ();
}
catch (SQLException ignore)
{
}
conn = null;
}
}
I would like to write much shorter:
Connection conn = null;
Statement stmt = null; // Or PreparedStatement if needed
ResultSet rs = null;
try
{
conn = ... get connection from connection pool ...
stmt = conn.createStatement ("select ...");
rs = stmt.executeQuery();
... iterate through the result set ...
}
catch (SQLException e)
{
// ... deal with errors ...
}
finally
{
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
try
{
if (rs != null)
rs.close ();
if (stmt != null)
stmt.close ();
if (conn != null)
conn.close ();
}
catch (SQLException ignore)
{
}
}
You have a good question - I don't understand the "official example" either. Finally block is certainly enough.
However, your code has more serious faults, namely if rs.close() would throw an exception, you'd have stmt and conn leaking out and you'd also ignore that exception silently. That is something you should not do. Since Java 7, using try-with-resources construct is the preferred way, but if you cannot go there, at least handle each possible exception (rs, stmt, conn) separately so they don't cause each other to leak.
For example Apache commons DbUtils has closeQuietly() just for this purpose, because it used to be a common scenario. Personally I would go to somewhere like Spring JDBCTemplate that does this sort of stuff behind the scenes.
Edit: try-with-resources is explained by Oracle here. In short, you'd do it something like this:
try (Connection conn = yourCodeToGetConnection();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + ", " + supplierID + ", " +
price + ", " + sales + ", " + total);
}
} catch (SQLException ex) {
// log, report or raise
}
Where the try-statement automatically deals with conn, stmt and rs closing in all cases and in order (the reverse order in which you state them). Possible exceptions you still need to handle yourself.
Thanks for the many comments. So summing up (especially EJP comments to my question [that closing a Connection will close underlying Statements and closing a Statement will it self close the ResultSet]) and as I consider the try-with-resource construct to be a bit difficult to read I suggest writing
Connection conn = null;
Statement stmt = null; // Or PreparedStatement if needed
ResultSet rs = null;
try
{
conn = ... get connection from connection pool ...
stmt = conn.createStatement ("select ...");
rs = stmt.executeQuery();
... iterate through the result set ...
}
catch (SQLException e)
{
// ... deal with errors ...
}
finally
{
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
try
{
if (conn != null)
conn.close ();
}
catch (SQLException ignore)
{
}
}
and closing only the main Connection while leaving the Statement and the ResultSet always untouched and to be closed by the Connection.
Right?
I will prefer writing a common method for closing the connection, which can be called from a finally block.
Something like this:
Connection conn = null;
Statement stmt = null; // Or PreparedStatement if needed
ResultSet rs = null;
try
{
conn = ... get connection from connection pool ...
stmt = conn.createStatement ("select ...");
rs = stmt.executeQuery();
... iterate through the result set ...
}
catch (SQLException e)
{
// ... deal with errors ...
}
finally
{
CloseTheConnection(conn);
CloseTheStatement(stmt);
}
public void closeTheConnection(Connection conn){
try{
if(conn!=null){
conn.close();
}
}catch(Exception ex){
}
public void closeTheStatement(Statement stmt){
try{
if( stmt != null)
stmt.close();
} catch(Exception ex){
}
}
By creating different methods and calling them from finally will ensure that even if you get any exception from one method the other method will definitely be called. And it will be reusable as well.
I having problem with my code:
ERROR: ORA-01000: maximum open cursor exceeded. This code is called from multiple threads.
Q. is oracle cursors are differen than JDBC cursor(resultset)?
public static void viewTable(Connection con, String TBName)
throws SQLException {
Statement stmt = null;
String query = "select *from " + TBName;
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String studentName = rs.getString("STD_NAME");
System.out.println(studentName + "\t");
}
} catch (SQLException e ) {
e.printStackTrace();
} finally {
if (stmt != null) { stmt.close(); }
}
}
Use try-with-resources to ensure that both statement and result set are closed.
String query = "select STD_NAME from " + TBName;
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
String studentName = rs.getString("STD_NAME");
System.out.println(studentName + "\t");
}
} // Closes rs and stmt even with exceptions.
You should always close the ResultSet and the Statement. As you said, your code is accessed by many thread so a lot of Resultset will be open and never
closed.
Put the ResultSet variable out of the try catch block and close it in a finally, beside the Statement closing.
This question already has answers here:
Where to close java PreparedStatements and ResultSets?
(13 answers)
Closed 8 years ago.
here is how I do it right now:
public static getConfs(Connection conn, String confNo){
ResultSet rs = null;
try{
rs = conn.createStatement().executeQuery("select col1,col2 from table1");
... // do something with rs
rs.getStatement().close();
rs = conn.createStatement().executeQuery("select col1,col2 from table2");
... // do somthing with rs
rs.getStatement().close();
rs = null;
}catch(Exception e){
throw e;
}finally{
if(rs != null){
try{
rs.getStatement().close();
}catch(SQLException se){
se.printStackTrace();
}
}
}
}
two questions:
1. should I reuse result set variable like that ?
2. is that good to close result set like that ? any smarter way?
Take a look at Spring JdbcUtils source, it closes ResultSet this way
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
logger.trace("Could not close JDBC ResultSet", ex);
} catch (Throwable ex) {
// We don't trust the JDBC driver: It might throw
// RuntimeException or Error.
logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
}
}
}
so your code would look like this
Statement st = conn.createStatement();
try {
ResultSet rs = st.executeQuery("select col1,col2 from table1");
// do something
closeResultSet(rs);
rs = st.executeQuery("select col1,col2 from table2");
// do something
closeResultSet(rs);
} finally {
// close Statement
}
Though in my opinion the best way not to work with JDBC at low level but use Spring JDBC directly. It thouroughly thought thru and will make your code simple and reliable.
i've occours this strange error for the first time in my life, and i don't know what does it means. I've a class that retrieve information from a table on a postgresql database, do some operations and return an arraylist with parsed element:
ResultSet rs = ProduttoreDCS.getProduttori();
System.out.println("Recuperato result set produttori");
ArrayList<String[]> res = new ArrayList<String[]>();
while (rs.next()) {
String[] current = new String[6];
current[0] = Integer.toString(rs.getInt("partita_iva"));
current[1] = rs.getString("nome");
current[2] = rs.getString("cognome");
current[3] = rs.getString("via_sede");
current[4] = rs.getString("citta_sede");
current[5] = rs.getString("provincia_sede");
res.add(current);
current = null;
}
return res;
the error is on "while" line.
public static ResultSet getProduttori() throws ClassNotFoundException, SQLException {
/*
* retrieve all record from produttori table
*/
Connection conn = null;
ResultSet res = null;
Statement stmt = null;
String query = "SELECT * FROM produttore";
conn = ConnectionManager.getConnection();
System.out.println("Connection obtained by ProduttoreDCS class");
stmt = conn.createStatement();
res = stmt.executeQuery(query);
stmt.close();
conn.close();
return res;
}
I've encountered the same problem by running the wrong combination of:
Postgres version;
Hibernate dialect;
postgres jdbc driver;
Updating all to the latest version solved the problem for me.
P.S. I know this is not what OP was asking, but this is the first result in Google when you search for the problem.
when you close the connection object in your getProduttori method, your result set will be automatically closed. when you try to re use it , it will be null.
ResultSet rs = ProduttoreDCS.getProduttori();
= null, as you have closed the connection in getProduttori
method, which will automatically close the resultset
thus, it returns null.
From Connection#close
Releases this Connection object's database and JDBC resources
immediately instead of waiting for them to be automatically released.
applies same when closing the Statement as well.For your code to work don't close Statement and Connection untill you get the rows.
#Baadshah has already shown you the standard way. If you are using java 7+ you can make use of try-with-resource block, which would make your life simpler.
try(Connection conn = gettheconn){
get the statement here
get the result set
perform your ops
}
catch(SQLException ex){
ex.printstacktrace();
}
If you observe, there is no finally block, your connection object will be closed once you exit the try block automatically.you don't have to explicity call Connection#close()
As per Docs
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 are closed the connection and then you are iterating ,where it is null.Please read the data and then close the connection.
A good practice here is
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn =
stmt = conn.prepareStatement("sql");
rs = stmt.executeQuery();
//DO SOME THING HERE
} catch {
// Error Handling
} finally {
try { if (rs != null) rs.close(); } catch (Exception e) {};
try { if (stmt != null) stmt.close(); } catch (Exception e) {};
try { if (conn != null) conn.close(); } catch (Exception e) {};
}
This is the problem:
stmt.close();
conn.close();
You're closing the connection to the database. You can't do that until you've read the data - otherwise how is the ResultSet going to read it? Maybe it will have read some data in to start with, but it's not meant to be a disconnected object.
In particular, from the docuemntation for ResultSet.close:
Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.
Closing the connection makes the resultSet go away.
A ResultSet is not a container you can use to pass data around in, it's only a wrapper around a cursor. You should run through the resultSet contents and copy them into a data structure, then return the data structure. You are already doing that, but you need to do it before closing the statement and connection.
Change the code to:
public static List<String[]> getProduttori() throws ClassNotFoundException, SQLException {
ArrayList<String[]> res = new ArrayList<String[]>();
/*
* retrieve all record from produttori table
*/
Connection conn = null;
ResultSet rs = null;
Statement stmt = null;
String query = "SELECT * FROM produttore";
conn = ConnectionManager.getConnection();
try {
System.out.println("Connection obtained by ProduttoreDCS class");
stmt = conn.createStatement();
try {
rs = stmt.executeQuery(query);
while (rs.next()) {
String[] current = new String[6];
current[0] = Integer.toString(rs.getInt("partita_iva"));
current[1] = rs.getString("nome");
current[2] = rs.getString("cognome");
current[3] = rs.getString("via_sede");
current[4] = rs.getString("citta_sede");
current[5] = rs.getString("provincia_sede");
res.add(current);
}
return res;
} finally {
try {
stmt.close();
} catch (SQLException e) {
log.error(e);
}
}
} finally {
try {
conn.close();
} catch (SQLException e) {
log.error(e);
}
}
}