+1
Wish there was a more elegant solution (like in Java 7)

On 12/10/13 6:01 AM, "Antonio ForniƩ Casarrubios"
<antonio.for...@gmail.com> wrote:

>Hi all,
>
>I'm trying to fix some typical "Resource Leak" issues in some cloudstack
>classes. An example could be Upgrade2214to30, but actually the very same
>issue can be found in many other classes.
>
>The reason for this mail is all these occurrences shall be fixed in a
>congruent way and I would like to know your thoughts about the following
>proposal:
>
>Let's see this exaple code
>
>01    PreparedStatement pstmt = conn.prepareStatement("SELECT bla bla
>bla");
>02    ResultSet rs = pstmt.executeQuery();
>03    while (rs.next()) {
>04        pstmt = conn.prepareStatement("INSERT INTO bla bla");
>05        pstmt.setLong(1, networkOfferingId);
>06        pstmt.executeUpdate();
>07     }
>
>
>In line 4 we assign a new PrepSt object to the same variable, so the
>previous object is lost and impossible to .close()  and the same will
>happen in each following iteration of the loop. Of course we cannot close
>the first PrepSt because that would also close the ResultSet and thus
>brake
>the loop, so we could create a second variable insertPstmt and change it
>like this:
>
>01    PreparedStatement pstmt = conn.prepareStatement("SELECT bla bla
>bla");
>02    ResultSet rs = pstmt.executeQuery();
>03    while (rs.next()) {
>04        PreparedStatement insertPstmt = conn.prepareStatement("INSERT
>INTO bla bla");
>05        insertPstmt.setLong(1, networkOfferingId);
>06        insertPstmt.executeUpdate();
>07        insertPstmt.close();
>08    }
>...
>15    finally{
>16        if (pstmt != null) {
>17            pstmt.close();
>18        }
>19    }
>
>This solution could be good for simple scenarios, but in some others we
>have several PrepSt open at the same time with 2 or 3 levels of nested
>loops... so this solution would mean creating plenty of PrepSt variables,
>which I think could be messy and error-prone...
>
>...and on top of that we end up repeating the same code in all the finally
>blocks of all the methods as we do now:
>
>            } finally {
>                try {
>                    if (rs != null) {
>                        rs.close();
>                    }
>
>                    if (pstmt != null) {
>                        pstmt.close();
>                    }
>                } catch (SQLException e) {
>                }
>            }
>
>
>I propose that in each of these cases we would do something like:
>00    List<PreparedStatement> pstmt2Close = new
>ArrayList<PreparedStatement>();
>01    PreparedStatement pstmt = conn.prepareStatement("SELECT bla bla
>bla");
>02    pstmt2Close.add(pstmt);
>03    ResultSet rs = pstmt.executeQuery();
>04    while (rs.next()) {
>05        pstmt = conn.prepareStatement("INSERT INTO bla bla");
>06        pstmt2Close.add(pstmt);
>06        pstmt.setLong(1, networkOfferingId);
>07        pstmt.executeUpdate();
>08    }
>...
>15    finally{
>16        closePstmts(pstmt2Close);
>17    }
>
>So we have a single List of Statements where I drop all of them as they
>are
>created and in the finally block I call this method:
>
>01    protected void closePstmts(List<PreparedStatement> pstmt2Close){
>02        for(PreparedStatement pstmt : pstmt2Close) {
>03            try {
>04                if (pstmt != null && !pstmt.isClosed()) {
>05                    pstmt.close();
>06                }
>07            } catch (SQLException e) {
>08                // It's not possible to recover from this and we need to
>continue closing
>09                e.printStackTrace();
>10            }
>11        }
>12    }
>
>
>Note1: Once a PreparedStatment is closed it's Resultset is closed too, so
>this method doesn't need more.
>Note2: We code the finally block only once and for all, instead of having
>different developers repeating the same or even worse, coding something
>different (Ana prints the Exception msg, Bob doesn't print and Carl throws
>a new Ex)
>
>Note3: For next versions of Java (from 1.7 on) PreparedStatement and other
>classes implement AutoCloseable, so we can have a list of AutoCloseable
>and
>if we want our method cleaner we can even use DbUtils.closeQuietly().
>
>If you guys don't see any drawbacks I will proceed and do the same in
>future similar scenarios.
>
>Thanks. Cheers
>antonio

Reply via email to