Where to close result set - java

I am getting result set is already closed where i am passing resultset into other method.where should i closed result set.
public void mainTest(){
ResultSet rs= pstmt.executeQuery(query);
List list = populateRS(rs);
if(rs!=null)rs.close();
}
public List populateRS(ResultSet rs){
//work with result set
if(rs!=null)rs.close();
}

You should probably use a try-finally block to close the ResultSet even if populateRS (or something else) throws an exception:
ResultSet rs;
try {
rs = pstmt.executeQuery(query);
List list = populateRS(rs);
} finally {
if (rs != null) {
rs.close();
}
}

Close in the same method you open in if at all possible. Consistently doing this makes it easy for code-reviewers and maintainers to easily triage resources into (obviously freed, obviously problematic, and needs more attention).
A few other notes:
Use try (...) or do the closing in finally so the resource is closed even when the code using it fails with an exception.
Use the #WillClose and #WillNotClose annotations as appropriate so that IDEs and tools like findbugs can point out problems.
public void mainTest(){
List<?> list;
try (ResultSet rs = pstmt.executeQuery(query)) {
list = populateRS(rs);
}
// work with list
}
public List<?> populateRS(#WillNotClose ResultSet rs){
//work with result set
}
or if you're stuck with older Java:
public void mainTest(){
List<?> list;
ResultSet rs = pstmt.executeQuery(query);
try {
list = populateRS(rs);
} finally {
if(rs!=null)rs.close();
}
// work with list
}

Use the new try-with-resources statement which would automatically close the ResultSet whether an exception occurs or not because it implements AutoCloseable.
The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement.
public void mainTest()
{
try (ResultSet rs = pstmt.executeQuery(query)) {
List list = populateRS(rs);
} catch (SQLException ex) {
}
}
public List populateRS(ResultSet rs){
// work with result set
}

It is good to close where you are opening .
It is good programming practise to close all resouces in finally block
public void mainTest()
{
ResultSet rs = null;
try{
rs= pstmt.executeQuery(query);
List list = populateRS(rs);
}finally{
try {
rs.close();
} catch (SQLException ex) {
}
}
}
public List populateRS(ResultSet rs){
//work with result set
}
according to java docs
Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.

Close things near where you open them. In this case that would be in the mainTest method after you call populateRS. If a method doesn't open something, it shouldn't close it.

You should close the ResultSet in the mainTest method to segregate populateRS method's participation in the lifecycle of the ResultSet.
You should have a finally block in which you should close the ResultSet. This practice gives you a guarantee that the ResultSet is closed even if an exception is thrown.

Related

DAO insert behavior doesnt seem normal

I made the DAO to create a sales offer and it is similar to an other DAO where it makes users and that connects and works. But the one below keeps skipping the if statements and I'm not sure why it isn't adding to the data base. I ran the same command in the SQL string in oracle and it worked there.
public boolean sendOffer(Sales sell) {
boolean done = false;
int key =0;
Connection conn = cu.getConnection();
try {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[]keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foriegn key
ps.setInt(3, sell.getCarID()); // forgien key
int number = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if(number!=1)
{
log.warn("data insert fail");
}
else
{
log.trace("success");
done=true;
}
if(rs.next()) {
key=rs.getInt(1);
sell.setID(key);
conn.commit();
}
else {
log.warn("data not found");
}
}catch(SQLException e)
{
}
finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
// TODO Auto-generated method stub
return done;
}'''
The main issue is that an exception is happening in your code but the try/catch block is intercepting it and swallowing it silently. While it may be tempting to catch and swallow exceptions, truth is it always causes more problems than it solves and the key concept of handling exceptions is to NOT handle them: just put the throws declaration and let the application crash.
You then have other possible side-issues depending on how the Connection was obtained in the first place, like the fact that you're never closing the PreparedStatement and the ResultSet (if the connection is closed, they are closed as well... but if the connection is returned to a pool then they are never going to be closed).
In general the above code tends to pack too much functionality in a single method and can quickly spiral out of control, so you might want to divide it in smaller chunks with clear individual responsibilities.
All of the above is common to observe wherever Connection and PreparedStatement are used directly, be it for maximum performance reasons or for lack of experience. Typically in web applications using the Spring framework this is solved through the use of a JdbcTemplate but I cannot assume that you are using Spring so I won't show its usage here.
At a minimum, I would modify your code roughly as follows:
public boolean sendOffer(Sales sell) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = cu.getConnection();
ps = prepareInsertOfferStatement(sell, conn);
ps.executeUpdate();
rs = ps.getGeneratedKeys();
sell.setID(extractKey(rs));
conn.commit();
log.trace("success");
return true;
}
catch(Exception ex) {
log.error(ex); // this is actually probably bad. Consider putting a throws declaration and get rid of this catch
return false;
}
finally {
closeQuietly(rs, ps, conn);
}
}
private void closeQuietly(AutoCloseable... objs) {
for(AutoCloseable obj : objs) {
try {
obj.close();
} catch (SQLException e) {
// this is usually mostly safe to ignore. Maybe log a warning somewhere
}
}
}
private PreparedStatement prepareInsertOfferStatement(Sales sell, Connection conn) throws SQLException {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[] keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foreign key
ps.setInt(3, sell.getCarID()); // foreign key
return ps;
}
private int extractKey(ResultSet rs) throws SQLException {
if(rs.next()) {
return rs.getInt(1);
}
else {
throw new Exception("The statement did not return any generated key.");
}
}
As you can see it's not shorter, but responsibilities are clearer and all objects are closed accordingly. Furthermore, it gives you nice reusable primitives to close connections and related objects and to extract the key from other inserts you will want to do. Further abstractions would allow you to obtain more primitives, but I think this is sufficient for you to get the gist of it.

Java try-with at complex apis

I want to wrap some JDBC code into my own and different classes. So the resource is created in those classes, the result set is returned. If the client is ready, then all in that chain opened resources should be closed.
I wrote the following, but I'm not sure if that is correct enough and the easiest way.
I build a SQL string for insertion of a data-row.
From my data source (hikari pool), I get a database connection. Then I create a prepared statement, I execute this and get a ResultSet back.
This result set I return to the caller.
The connection and prepared statement have to remain open, until the caller is ready with that returned result set
public DbResult insert(int cache, String shema, String table, LinkedHashMap<String, Object> data, boolean returnAutoCreate) throws SQLException
{
//building sql-string or take it from my cache
//...
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try
{
connection = ds.getConnection();
preparedStatement = connection.prepareStatement(sqlString);
int i = 0;
for (Object value : data.values())
{
preparedStatement.setObject(i++, value);
}
preparedStatement.executeUpdate();
resultSet = preparedStatement.getResultSet();
DbResult dbResult = new DbResult(connection, preparedStatement, resultSet);
return dbResult;
}
catch (Exception e)
{
try
{
if (resultSet != null) resultSet.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (preparedStatement != null) preparedStatement.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (connection != null) connection.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
throw e;
}
}
Here is my DbResult class
class DbResult implements AutoCloseable
{
private final ResultSet rs;
private final PreparedStatement ps;
private final Connection conn;
public DbResult(Connection conn, PreparedStatement ps, ResultSet rs)
{
this.conn = conn;
this.ps = ps;
this.rs = rs;
}
#Override
public void close() throws SQLException
{
try (conn; ps; rs;){}
}
public ResultSet getResultSet()
{
return rs;
}
}
And here the client/caller-code
DatabaseHelper databaseHelper = new DatabaseHelper(ds, defaultShema);
try(DbResult result = databaseHelper.insert(1001, defaultShema, "test", new LinkedHashMap<>(), true);)
{
//do sth with result
}
In my insert method I added that try catch, cause if something fails there, I must close the resources.
If there is no problem, I add the resources to my DbResult object, and there I close the resources with the close()-method. In that, I use a try-with, cause if in that chain one close fails, then the others are still closed, and the exception is forwarded correctly.
At my caller, I use also a try-with, which calls that close()-method in DbResult after I'm done with the result.
But it's a lot of code, especially the try-catch construct in my insert-method.
I'm not sure, if there is a easier or a better way of doing that.
One more question I have:
I could cache the result, so I don't have to take care of that resource closing outside of my DatabaseHelper class.
There exists a CachedRowSet. But I'm not sure about, how expensive this is. Does that copy also the MetaInformations?
I guess the normal ResultSet retrieves the data first, if I access them:
the meta data, the row-data: row by row?
Is that a good idea to cache the data into ArrayList of Hashmaps?
Arraylist -> Rows
HashMap -> coloums by name -> value
So if I do that, I can close all resources immediately.
-> I don't have to care about that closing outside of my DatabaseClass
-> the pool gets the connection faster back
However, maybe I retrieve data, which I don't need (for example, the meta data).
Also, it's expensive to build a copy of my data into a ArrayList->Hashmap construct.
So what ideas do you have of that; whats the best practice?

Possible Findbug false positive for "obl_unsatisfied_obligation"

I have a code section like bellow:
try (UnitOfWork unitOfWork = datasource.getConnection()) {
ResultSet resultset = untiOfWork.getStatement().getResultSet();
unitOfWork.queueToClose(resultSet);
...
}
The UnitOfWork is an AutoClosable. So inside of the UnitOfWork close() method is like this.
#Overide
public void close() {
for (AutoClosable closable : queueToClose) {
closable.close();
}
connection.close();
}
Now the FindBug is complaining about the ResultSet is not being closed. Is this a false positive? Is this a bad pattern?
In addition to the excellent answer that 'Alexey Romanov' posted there is a potential leak in your implementation of UnitOfWork.close where if any of those close calls throws an exception your connection is not closed.
#Override
public void close() throws Exception {
Exception first = null;
try (AutoCloseable requiredForJdk8 = this.connection) {
for (AutoCloseable closable : this.queueToClose) {
try {
closable.close();
} catch (Exception e) {
if (first == null) {
first = e;
} else {
if (first != e) {
first.addSuppressed(e);
}
}
}
}
if (first != null){
throw first;
}
}
}
It is a false positive in the sense that ResultSet will be closed, but there is no way for FindBugs to know this.
It is also a bad pattern: what happens if you forget to call queueToClose after getting a ResultSet? Does UnitOfWork.getStatement() add the statement to queueToClose before returning it?
Better would be
try (UnitOfWork unitOfWork = datasource.getConnection();
Statement statement = unitOfWork.getStatement();
ResultSet resultset = statement.getResultSet()) {
...
}

Is a pooled db-access using method-level connection in a static class/method safe?

have been a long-time reader here and now I`ve got a problem I canĀ“t really get my head around.
For ease of access and to save object creation overhead I have a static class realizing database accesses. The used JVM implementation is Tomcat and for connection pooling org.apache.commons.dbcp is used.
I've read a lot about thread-safety, heap and stack here and elsewhere but I can`t get to a definitive conclusion if multiple method calls on my static class won't interfere with each other. Most topics I've read deal with instance methods while I use static ones which might have implications I overlooked.
If I understood everything correctly, as the variables connection, statement, resultset are on the method level, each function call should have a unique reference on the stack to a unique object in the heap and it should not be possible that multiple method calls interfere with each other.
Am I right or do I stand corrected? Any help would be appreciated.
The (shortened) code is :
public class DBQuery{
private static String pathToDataSource = "";
private static javax.naming.Context cxt = null;
private static javax.sql.DataSource ds = null;
private static void getDataSource() throws Exception {
if(pathToDataSource.equals("")){ pathToDataSource = Config.getParam("PathToDataSource"); }
cxt = new javax.naming.InitialContext();
ds = (javax.sql.DataSource) cxt.lookup(pathToDataSource);
}
private static Connection connect() throws Exception {
if(ds==null){ getDataSource(); }
return ds.getConnection();
}
public static Vector doDBquery(String querystring) throws Exception {
Vector retVec = new Vector();
Connection connection = null;
Statement statement = null;
ResultSet resultset = null;
try {
connection = getConnection();
statement = connection.createStatement();
resultset = statement.executeQuery(querystring);
...
} catch(Exception e) {
...
} finally {
myFinallyBlock(resultset, statement, connection);
}
return retVec;
}
// more methods like doDBInsert() following, hence closure in separate myFinallyBlock
private static void myFinallyBlock(ResultSet resultset, Statement statement, Connection connection) {
try {
if (resultset != null) resultset.close();
} catch (SQLException e) { resultset = null; }
try {
if (statement != null) statement.close();
} catch (SQLException e) { statement = null; }
try {
if (connection != null) connection.close();
} catch (SQLException e) { connection = null; }
}
} //close class
Yeah, you are right inside method there is no concurrency problems , until you are using shared variables inside it, in other words "Stateless objects are always thread-safe."
Servlet is quite good example of it ;)
edited.
For making your code safe I recommend you to do follow:
private static Connection connect() throws Exception {
if (ds == null) {
synchronized (Connection.class) {
if (ds == null) {
getDataSource();
}
}
}
return ds.getConnection();
}

Can I use the same connection object when calling within Methods?

I have got a program this way:
public void MethodOne()
{
String sqlquery = "select * from vendor_items where category_id = 1 ";
PreparedStatement consildatedPst = connection.prepareStatement(sqlquery);
ResultSet consilatedReslset = consildatedpst.executeQuery();
while(consilatedReslset.next())
{
String name = consilatedReslset.getString("name");
if(name!=null)
{
MethodTwo();
}
}
}
public void MethodTwo(String name)
{
String sqlquery2 = "select ename from Vendor where name=?";
PreparedStatement otherPst = connection.prepareStatement(sqlquery2);
otherPst.setString(1,name);
}
This is the way connection is established (Later I will go for Connection Pooling).
public class DBConnection {
public static Connection getDBConnection() {
String sURL="jdbc:mysql://localhost:3306/oms";
String sUserName="root";
String sPwd="";
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(sURL, sUserName,sPwd);
return conn;
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
}
My question is Can I use the same connection object when calling within Methods??
Yes, you can.
When you do:
connection.prepareStatement(sqlquery2);
It creates a new statement object using the same connection. So the ResultSets that you obtain from them will belong to different Statements and will be different and there will be NO PROBLEM for you.
In short: Different Statements manage different ResultSets. If you get 2 ResultSets from the same Statement when you get the second one the first one will be dropped but if you have 2 Statements you can manage 2 ResulSets without problem (while the connection is open, of course)
Only if you aren't using the connection in multiple threads or nesting your own methods. In other words, no. Use a new connection per method. To avoid overhead use a connection pool.

Categories