Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #37077 > unrolled thread

Is this the way to work with try with resources

Started byCecil Westerhof <Cecil@decebal.nl>
First post2017-08-08 13:26 +0200
Last post2017-08-09 06:39 +0200
Articles 20 on this page of 30 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-08 13:26 +0200
    Re: Is this the way to work with try with resources Martin Gregorie <martin@address-in-sig.invalid> - 2017-08-08 12:51 +0000
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:10 +0200
    Re: Is this the way to work with try with resources Patrick Roemer <sangamon@netcologne.de> - 2017-08-08 18:29 +0200
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:20 +0200
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:16 +0200
    Re: Is this the way to work with try with resources Patrick Roemer <sangamon@netcologne.de> - 2017-08-08 19:30 +0200
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 06:49 +0200
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:01 +0200
      Re: Is this the way to work with try with resources Patrick Roemer <sangamon@netcologne.de> - 2017-08-09 15:39 +0200
    Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-08 21:25 -0400
      Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-08 21:36 -0400
        Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:29 +0200
          Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-09 20:53 -0400
            Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-09 23:03 -0400
      Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-08 21:48 -0400
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 07:24 +0200
    Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 06:26 +0200
      Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 08:30 +0200
      Re: Is this the way to work with try with resources Andreas Leitgeb <avl@logic.at> - 2017-08-09 09:40 +0000
        Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 12:56 +0200
          Re: Is this the way to work with try with resources Andreas Leitgeb <avl@logic.at> - 2017-08-09 16:51 +0000
            Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 19:37 +0200
              Re: Is this the way to work with try with resources Andreas Leitgeb <avl@logic.at> - 2017-08-09 19:51 +0000
                Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 22:20 +0200
                  Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 23:17 +0200
            Re: Is this the way to work with try with resources Patrick Roemer <sangamon@netcologne.de> - 2017-08-09 22:08 +0200
          Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-09 18:07 -0400
      Re: Is this the way to work with try with resources Arne Vajhøj <arne@vajhoej.dk> - 2017-08-09 18:05 -0400
    Re: Is this the way to work with try with resources Cecil Westerhof <Cecil@decebal.nl> - 2017-08-09 06:39 +0200

Page 1 of 2  [1] 2  Next page →


#37077 — Is this the way to work with try with resources

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-08 13:26 +0200
SubjectIs this the way to work with try with resources
Message-ID<87poc6wb9n.fsf@munus.decebal.nl>
When using with resources you ‘should’ always work with try with
resources. At the moment I have something like the following code:
    private static void statistics() {
        try (Statement stmt = conn.createStatement()) {
            String format;

            try (ResultSet rsTotal = stmt.executeQuery(COUNT_TOTAL_PROV)) {
                final int count = rsTotal.getInt("no");

                format = String.format("There are %%,%dd %%6s proverbs.%%n", String.format("%,d", count).length());
                System.out.printf(format, count, "total");
            }
            try (ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV)) {
                final int count = rsUnused.getInt("no");

                if (count != 0) {
                    System.out.printf(format, count, "unused");
                }
            }
            try (ResultSet rsUsed = stmt.executeQuery(COUNT_USED_PROV)) {
                final int count = rsUsed.getInt("no");

                System.out.printf(format, count, "used");
            }
        } catch (SQLException e) {
            System.err.printf("Error in statistics\n");
            e.printStackTrace();
            fatalError("");
        }
    }

It feels a bit long-winded. Is this the way to go, or is there a
better way?


I thought that I could rewrite it to:
    private static void statistics() {
        try (Statement stmt     = conn.createStatement();
             ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
             ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
             ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
            int    count;
            String format;

            count  = rsTotal.getInt("no");
            format = String.format("There are %%,%dd %%6s proverbs.%%n", String.format("%,d", count).length());
            System.out.printf(format, count, "total");
            count  = rsUnused.getInt("no");
            if (count != 0) {
                System.out.printf(format, count, "unused");
            }
            count  = rsUsed.getInt("no");
            System.out.printf(format, count, "used");
        } catch (SQLException e) {
            System.err.printf("Error in statistics\n");
            e.printStackTrace();
            fatalError("");
        }
    }

That would be a little better I think, but when there are a lot of
queries to be done, you need to define a lot of extra result-sets.

But there is a problem with that. If I do that, all three result-sets
have the same query: the last one.
What is the reason for this? I am using SQLite3.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#37079

FromMartin Gregorie <martin@address-in-sig.invalid>
Date2017-08-08 12:51 +0000
Message-ID<omcc5d$uk9$1@dont-email.me>
In reply to#37077
On Tue, 08 Aug 2017 13:26:44 +0200, Cecil Westerhof wrote:

> When using with resources you ‘should’ always work with try with
> resources. At the moment I have something like the following code:
>     private static void statistics() {
>         try (Statement stmt = conn.createStatement()) {
>             String format;
> 
>             try (ResultSet rsTotal =
>             stmt.executeQuery(COUNT_TOTAL_PROV)) {
>                 final int count = rsTotal.getInt("no");
> 
>                 format = String.format("There are %%,%dd %%6s
>                 proverbs.%%n", String.format("%,d", count).length());
>                 System.out.printf(format, count, "total");
>             }
>             try (ResultSet rsUnused =
>             stmt.executeQuery(COUNT_UNUSED_PROV)) {
>                 final int count = rsUnused.getInt("no");
> 
>                 if (count != 0) {
>                     System.out.printf(format, count, "unused");
>                 }
>             }
>             try (ResultSet rsUsed = stmt.executeQuery(COUNT_USED_PROV))
>             {
>                 final int count = rsUsed.getInt("no");
> 
>                 System.out.printf(format, count, "used");
>             }
>         } catch (SQLException e) {
>             System.err.printf("Error in statistics\n");
>             e.printStackTrace();
>             fatalError("");
>         }
>     }
> 
> It feels a bit long-winded. Is this the way to go, or is there a better
> way?
> 
> 
> I thought that I could rewrite it to:
>     private static void statistics() {
>         try (Statement stmt     = conn.createStatement();
>              ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>              ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>              ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
>             int    count;
>             String format;
> 
>             count  = rsTotal.getInt("no");
>             format = String.format("There are %%,%dd %%6s proverbs.%%n",
>             String.format("%,d", count).length());
>             System.out.printf(format, count, "total");
>             count  = rsUnused.getInt("no");
>             if (count != 0) {
>                 System.out.printf(format, count, "unused");
>             }
>             count  = rsUsed.getInt("no");
>             System.out.printf(format, count, "used");
>         } catch (SQLException e) {
>             System.err.printf("Error in statistics\n");
>             e.printStackTrace();
>             fatalError("");
>         }
>     }
> 
In the absence of any other information I prefer the second organisation. 

In general, if you have a set of queries that are related so that if any 
of them fail, the results returned by the others are useless, then its 
sensible to put the lot in a single try...catch block. If the results 
should be treated as independent of whether any of the others fail, then 
they should be in separate try...catch blocks. 

If the queries update the database then all the queries that must either 
all succeed or all fail should be grouped into a commitment unit and this 
should by included in the one try...catch block, since, if there is any 
failure you'll want to roll back the whole commitment unit.

> But there is a problem with that. If I do that, all three result-sets
> have the same query: the last one.
> 
> What is the reason for this? I am using SQLite3.
>
Thats difficult to answer knowing how ACID compliant SQLite3 is and 
whether it is assuming that each query is being run in an automatic 
commitment unit: reuse of "no", presumably a column name, in all three 
statements bothers me a bit and so does the fact that you've executed all 
three queries before asking for any results. As I result of both these 
factors I think you've ended up retrieving the result from the LAST query 
three times. 

It should work as expected if each query is executed immediately before 
calling getInt() to  retrieve and print its result.


-- 
martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

[toc] | [prev] | [next] | [standalone]


#37099

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:10 +0200
Message-ID<871solwclq.fsf@munus.decebal.nl>
In reply to#37079
Martin Gregorie <martin@address-in-sig.invalid> writes:

> On Tue, 08 Aug 2017 13:26:44 +0200, Cecil Westerhof wrote:
>
>> I thought that I could rewrite it to:
>>     private static void statistics() {
>>         try (Statement stmt     = conn.createStatement();
>>              ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>>              ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>>              ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
>>             int    count;
>>             String format;
>> 
>>             count  = rsTotal.getInt("no");
>>             format = String.format("There are %%,%dd %%6s proverbs.%%n",
>>             String.format("%,d", count).length());
>>             System.out.printf(format, count, "total");
>>             count  = rsUnused.getInt("no");
>>             if (count != 0) {
>>                 System.out.printf(format, count, "unused");
>>             }
>>             count  = rsUsed.getInt("no");
>>             System.out.printf(format, count, "used");
>>         } catch (SQLException e) {
>>             System.err.printf("Error in statistics\n");
>>             e.printStackTrace();
>>             fatalError("");
>>         }
>>     }
>> 
> In the absence of any other information I prefer the second organisation. 

I have done that now. I found the reason the above went wrong: a
Statement can only have one concurrent ResultSet. See my reply on my
own post.


>> But there is a problem with that. If I do that, all three result-sets
>> have the same query: the last one.
>> 
>> What is the reason for this? I am using SQLite3.
>>
> Thats difficult to answer knowing how ACID compliant SQLite3 is and

I need to read the JDBC specs. When creating a new ResultSet the old
one(s) get overwritten with the new one. (Not closed as the specs
say.)


> commitment unit: reuse of "no", presumably a column name, in all
> three

I probably should rename that to count. ;-)


> statements bothers me a bit and so does the fact that you've executed all 
> three queries before asking for any results.

That is the only way to have only one try with resources.


> As I result of both these 
> factors I think you've ended up retrieving the result from the LAST query 
> three times. 

Yes, I need to have a separate Statement for each ResultSet. That is
the way I implemented it now.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37085

FromPatrick Roemer <sangamon@netcologne.de>
Date2017-08-08 18:29 +0200
Message-ID<omcou4$lkj$1@newsreader4.netcologne.de>
In reply to#37077
Responding to Cecil Westerhof:
>         try (Statement stmt     = conn.createStatement();
>              ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>              ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>              ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
[...]
>         } catch (SQLException e) {
[...]
>         }

| By default, only one ResultSet object per Statement object can be open
| at the same time. Therefore, if the reading of one ResultSet object is
| interleaved with the reading of another, each must have been generated
| by different Statement objects. All execution methods in the Statement
| interface implicitly close a current ResultSet object of the statement
| if an open one exists.
https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#37100

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:20 +0200
Message-ID<87shh1uxjx.fsf@munus.decebal.nl>
In reply to#37085
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Patrick Roemer <sangamon@netcologne.de> writes:
>>| By default, only one ResultSet object per Statement object can be open
>>| at the same time. Therefore, if the reading of one ResultSet object is
>
>   Ok. As far as I understand it, the refactoring posted by me
>   does not suffer from violations against this restriction.
>
>   Still, I have revised my code so as to make the try regions
>   for the statements as small as possible in order to make it
>   readably clear that there is no such violation:
>
>   (Note that especially »makeFormatAndContinue()« now is
>   evaluated outside of the scope of »rsTotal«, so now there
>   are no result sets that even have overlapping lifetimes.)
>
> private static java.sql.Statement statement;
> private static int count;
> private static java.lang.String format;
>
> private static void printTotal() 
> { System.out.printf( format, count, "total" );  }
>
> private static void printUnused() 
> throws java.sql.SQLException
> { int countUnused = 0;
>   try( final java.sql.ResultSet rsUnused = statement.executeQuery( COUNT_UNUSED_PROV )) 
>   { countUnused = rsUnused.getInt( "no" ); }
>   if( countUnused != 0 )java.lang.System.out.printf( format, count, "unused" ); }
>
> private static void printUsed() 
> throws java.sql.SQLException
> { int countUsed = -1;
>   try( final java.sql.ResultSet rsUsed = statement.executeQuery( COUNT_USED_PROV )) 
>   { countUsed = rsUsed.getInt( "no" ); }
>   java.lang.System.out.printf( format, countUsed, "used" ); }
>
> private static void printAllStatistics() 
> throws java.sql.SQLException
> { printTotal();
>   printUnused();
>   printUsed(); }
>
> private static void makeFormatAndContinue()
> throws java.sql.SQLException
> { format = java.lang.String.format
>   ( "There are %%,%dd %%6s proverbs.%%n", java.lang.String.format( "%,d", count ).length() );
>   printAllStatistics(); }
>
> private static void makeCountAndContinue() 
> throws java.sql.SQLException
> { try( final java.sql.ResultSet rsTotal = statement.executeQuery( COUNT_TOTAL_PROV )) 
>   { count = rsTotal.getInt( "no" ); }
>   makeFormatAndContinue(); }
>
> private static void makeStatementAndContinue() 
> { try( final java.sql.Statement s = conn.createStatement() ) 
>   { statement = s; makeCountAndContinue(); }
>   catch( final java.sql.SQLException exception ) 
>   { java.lang.System.err.println( "Error in statistics" );
>     exception.printStackTrace();
>     fatalError( "" ); }}
>
> private static void printStatistics() 
> { makeStatementAndContinue(); }
>
> public static void main( final java.lang.String[] args ) 
> { java.lang.System.out.println( "OK" ); }}

Looks interesting, but personally I find it to complex.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37102

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:16 +0200
Message-ID<87wp6duxri.fsf@munus.decebal.nl>
In reply to#37085
Patrick Roemer <sangamon@netcologne.de> writes:

> Responding to Cecil Westerhof:
>>         try (Statement stmt     = conn.createStatement();
>>              ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>>              ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>>              ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
> [...]
>>         } catch (SQLException e) {
> [...]
>>         }
>
> | By default, only one ResultSet object per Statement object can be open
> | at the same time. Therefore, if the reading of one ResultSet object is
> | interleaved with the reading of another, each must have been generated
> | by different Statement objects. All execution methods in the Statement
> | interface implicitly close a current ResultSet object of the statement
> | if an open one exists.
> https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html

Yes, I found that out. I now do not generate a explicit Statement
anymore and do something like:
        try (ResultSet rsTotal  = conn.createStatement().executeQuery(COUNT_TOTAL_PROV);
             ResultSet rsUnused = conn.createStatement().executeQuery(COUNT_UNUSED_PROV);
             ResultSet rsUsed   = conn.createStatement().executeQuery(COUNT_USED_PROV)) {

It generates three ResultSet and three implicit Statement, but that is
probably no problem.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37087

FromPatrick Roemer <sangamon@netcologne.de>
Date2017-08-08 19:30 +0200
Message-ID<omcsep$org$1@newsreader4.netcologne.de>
In reply to#37077
Responding to Stefan Ram:
> Cecil Westerhof <Cecil@decebal.nl> writes:
>>It feels a bit long-winded.
> 
>   Yes. The method is too long. We need to refactor.

Up to here we agree. ;)

I'd rather move towards something like this:

<snip>
private static void statistics(Connection conn) {
  try (Statement stmt = conn.createStatement()) {
    String format = runQueryFun(stmt, COUNT_TOTAL_PROV,
        rs -> totalStats(rs.getInt("no")));
    runQueryProc(stmt, COUNT_UNUSED_PROV,
        rs -> unusedStats(format, rs.getInt("no")));
    runQueryProc(stmt, COUNT_USED_PROV,
        rs -> usedStats(format, rs.getInt("no")));
  }
  catch (SQLException e) {
    System.err.printf("Error in statistics\n");
    e.printStackTrace();
    fatalError(""); // wat?!
  }
}
</snip>

- runQuery[Fun|Proc] and associated interfaces could go to a reusable
toolbox
- all JDBC jazz is confined to this method; all methods called from here
are JDBC agnostic

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#37097

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 06:49 +0200
Message-ID<87a839wdjs.fsf@munus.decebal.nl>
In reply to#37087
Patrick Roemer <sangamon@netcologne.de> writes:

> Responding to Stefan Ram:
>> Cecil Westerhof <Cecil@decebal.nl> writes:
>>>It feels a bit long-winded.
>> 
>>   Yes. The method is too long. We need to refactor.
>
> Up to here we agree. ;)
>
> I'd rather move towards something like this:
>
> <snip>
> private static void statistics(Connection conn) {
>   try (Statement stmt = conn.createStatement()) {
>     String format = runQueryFun(stmt, COUNT_TOTAL_PROV,
>         rs -> totalStats(rs.getInt("no")));
>     runQueryProc(stmt, COUNT_UNUSED_PROV,
>         rs -> unusedStats(format, rs.getInt("no")));
>     runQueryProc(stmt, COUNT_USED_PROV,
>         rs -> usedStats(format, rs.getInt("no")));
>   }
>   catch (SQLException e) {
>     System.err.printf("Error in statistics\n");
>     e.printStackTrace();
>     fatalError(""); // wat?!
>   }
> }
> </snip>

Does not completely what I did, but I found a solution that does
something like this. See my reply on my own post.

It is just a desktop application. So I have a method fatalError which
prints an error if necessary and ‘cleanly’ exists the application.
    private static void fatalError(String message) {
        if (!message.equals("")) {
            System.err.println(message);
        }
        deinit(1);
    }

And the deinit method:
    private static void deinit(int exitCode) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                System.err.printf("deinit: Could not close the connection\n");
            }
            conn = null;
        }
        System.exit(exitCode);
    }

I know that in principle the connection does not need to be closed,
but I prefer to do it.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37098

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:01 +0200
Message-ID<8760dxwd0j.fsf@munus.decebal.nl>
In reply to#37087
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Patrick Roemer <sangamon@netcologne.de> writes:
>>I'd rather move towards something like this:
>>String format = runQueryFun(stmt, COUNT_TOTAL_PROV,
>>    rs -> totalStats(rs.getInt("no")));
>>runQueryProc(stmt, COUNT_UNUSED_PROV,
>>    rs -> unusedStats(format, rs.getInt("no")));
> ...
>>- runQuery[Fun|Proc] and associated interfaces could go to a reusable
>>toolbox
>>- all JDBC jazz is confined to this method; all methods called from here
>>are JDBC agnostic
>
>   Excellent idea! I always like to separate parts of a library
>   according to the system (like JDBC) they deal with. I think
>   that this is also an important aspect of MVC, where the VC
>   contains GUI stuff, while the M contains non-GUI stuff.
>
>   I think you might mean something along the lines of (untested):
>
> private static void 
> runQueryProc 
> ( final java.sql.Statement statement,
>   final java.lang.String query,
>   final java.util.function.Consumer< java.sql.ResultSet >consumer )
> throws java.sql.SQLException
> { try( final java.sql.ResultSet set = statement.executeQuery( query )) 
>   { consumer.accept( set ); }}
>
> private static< T >T 
> runQueryFun 
> ( final java.sql.Statement statement,
>   final java.lang.String query,
>   final java.util.function.Function< java.sql.ResultSet, T > function )
> throws java.sql.SQLException
> { T result = null;
>   try( final java.sql.ResultSet set = statement.executeQuery( query )) 
>   { result = function.apply( set ); }
>   return result; }

Looks interesting. For the moment I found a solution. But this is
certainly something to look at.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37111

FromPatrick Roemer <sangamon@netcologne.de>
Date2017-08-09 15:39 +0200
Message-ID<omf3ad$ein$1@newsreader4.netcologne.de>
In reply to#37087
Responding to Stefan Ram:
> private static void 
> runQueryProc 
> ( final java.sql.Statement statement,
>   final java.lang.String query,
>   final java.util.function.Consumer< java.sql.ResultSet >consumer )
> throws java.sql.SQLException
> { try( final java.sql.ResultSet set = statement.executeQuery( query )) 
>   { consumer.accept( set ); }}
[...]

Yep, but you'll need custom interfaces instead of Consumer/Function to
cater for the SQLException.

Best regards,
Patrick

[toc] | [prev] | [next] | [standalone]


#37092

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-08 21:25 -0400
Message-ID<omdob4$cif$1@gioia.aioe.org>
In reply to#37077
On 8/8/2017 7:26 AM, Cecil Westerhof wrote:
> When using with resources you ‘should’ always work with try with
> resources. At the moment I have something like the following code:
>      private static void statistics() {
>          try (Statement stmt = conn.createStatement()) {
>              String format;
> 
>              try (ResultSet rsTotal = stmt.executeQuery(COUNT_TOTAL_PROV)) {
>                  final int count = rsTotal.getInt("no");
> 
>                  format = String.format("There are %%,%dd %%6s proverbs.%%n", String.format("%,d", count).length());
>                  System.out.printf(format, count, "total");
>              }
>              try (ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV)) {
>                  final int count = rsUnused.getInt("no");
> 
>                  if (count != 0) {
>                      System.out.printf(format, count, "unused");
>                  }
>              }
>              try (ResultSet rsUsed = stmt.executeQuery(COUNT_USED_PROV)) {
>                  final int count = rsUsed.getInt("no");
> 
>                  System.out.printf(format, count, "used");
>              }
>          } catch (SQLException e) {
>              System.err.printf("Error in statistics\n");
>              e.printStackTrace();
>              fatalError("");
>          }
>      }
> 
> It feels a bit long-winded. Is this the way to go, or is there a
> better way?

That code looks like try with resource is intended to be used

> I thought that I could rewrite it to:
>      private static void statistics() {
>          try (Statement stmt     = conn.createStatement();
>               ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>               ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>               ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {

As already mentioned by somebody else then executing multiple queries
on the same connection and statement is not safe.

And even if you modified the code to work on different connections and
statements, then it would sort of violate good database programming
practice by opening more stuff and keeping stuff open longer than
needed.

It would also require all readers of your code to know that close
is called in reverse order for the code to look good in their eyes.

Bottom line: bad!

>              int    count;
>              String format;
> 
>              count  = rsTotal.getInt("no");
>              format = String.format("There are %%,%dd %%6s proverbs.%%n", String.format("%,d", count).length());
>              System.out.printf(format, count, "total");
>              count  = rsUnused.getInt("no");
>              if (count != 0) {
>                  System.out.printf(format, count, "unused");
>              }
>              count  = rsUsed.getInt("no");
>              System.out.printf(format, count, "used");
>          } catch (SQLException e) {
>              System.err.printf("Error in statistics\n");
>              e.printStackTrace();
>              fatalError("");
>          }
>      }
> 
> That would be a little better I think, but when there are a lot of
> queries to be done, you need to define a lot of extra result-sets.
> 
> But there is a problem with that. If I do that, all three result-sets
> have the same query: the last one.
> What is the reason for this? I am using SQLite3.

New SQL statement => result from previous SQL statement is
discarded.

Arne


[toc] | [prev] | [next] | [standalone]


#37093

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-08 21:36 -0400
Message-ID<omdovg$d4o$1@gioia.aioe.org>
In reply to#37092
On 8/8/2017 9:25 PM, Arne Vajhøj wrote:
> On 8/8/2017 7:26 AM, Cecil Westerhof wrote:
>> When using with resources you ‘should’ always work with try with
>> resources. At the moment I have something like the following code:
>>      private static void statistics() {
>>          try (Statement stmt = conn.createStatement()) {
>>              String format;
>>
>>              try (ResultSet rsTotal = 
>> stmt.executeQuery(COUNT_TOTAL_PROV)) {
>>                  final int count = rsTotal.getInt("no");
>>
>>                  format = String.format("There are %%,%dd %%6s 
>> proverbs.%%n", String.format("%,d", count).length());
>>                  System.out.printf(format, count, "total");
>>              }
...
>>          } catch (SQLException e) {
>>              System.err.printf("Error in statistics\n");
>>              e.printStackTrace();
>>              fatalError("");
>>          }
>>      }
>>
>> It feels a bit long-winded. Is this the way to go, or is there a
>> better way?
> 
> That code looks like try with resource is intended to be used

I would do it like that.

If you absolutely want to make the code shorter no matter the cost,
then just drop the try and do not put in anything else to call close.

And then cross your fingers and pray that whoever implemented the
JDBC driver(s) you are using did read the JDBC specs section
stating that Statement close (called implicit in this case) will
also close ResultSet for that Statement.

I would not do that.

Arne

[toc] | [prev] | [next] | [standalone]


#37101

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:29 +0200
Message-ID<87k22dux5g.fsf@munus.decebal.nl>
In reply to#37093
Arne Vajhøj <arne@vajhoej.dk> writes:

> If you absolutely want to make the code shorter no matter the cost,
> then just drop the try and do not put in anything else to call close.

Not no matter what the cost. ;-)
And certainly not without a try.


> And then cross your fingers and pray that whoever implemented the
> JDBC driver(s) you are using did read the JDBC specs section
> stating that Statement close (called implicit in this case) will
> also close ResultSet for that Statement.

I now have:
        try (ResultSet rsTotal  = conn.createStatement().executeQuery(COUNT_TOTAL_PROV);
             ResultSet rsUnused = conn.createStatement().executeQuery(COUNT_UNUSED_PROV);
             ResultSet rsUsed   = conn.createStatement().executeQuery(COUNT_USED_PROV)) {

That could go wrong? If so: is there a way to verify if it goes OK, or
wrong?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37121

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-09 20:53 -0400
Message-ID<omgapf$dlf$1@gioia.aioe.org>
In reply to#37101
On 8/9/2017 1:29 AM, Cecil Westerhof wrote:
> I now have:
>          try (ResultSet rsTotal  = conn.createStatement().executeQuery(COUNT_TOTAL_PROV);
>               ResultSet rsUnused = conn.createStatement().executeQuery(COUNT_UNUSED_PROV);
>               ResultSet rsUsed   = conn.createStatement().executeQuery(COUNT_USED_PROV)) {
> 
> That could go wrong?

Lots.

See previous posts.

>                   If so: is there a way to verify if it goes OK, or
> wrong?

Interesting question.

There are probably many approaches.

But here is one.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DBCode {
     public static void main(String[] args) throws SQLException {
         Connection con = 
DriverManager.getConnection("jdbc:mysql://localhost/Test", "root", "");
         con = Reveal.wrap(con); // <----
         Statement stmt = con.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT f1,f2 fROM t1");
         while(rs.next()) {
             System.out.printf("%d %s\n",  rs.getInt(1), rs.getString(2));
         }
         //rs.close();
         //stmt.close();
         PreparedStatement pstmt = con.prepareStatement("SELECT f1,f2 
fROM t1 WHERE f1 > ?");
         pstmt.setInt(1, 2);
         ResultSet prs = pstmt.executeQuery();
         while(prs.next()) {
             System.out.printf("%d %s\n",  prs.getInt(1), prs.getString(2));
         }
         //prs.close();
         //pstmt.close();
         //con.close();
         Reveal.dumpOpen(System.out); // <----
     }
}

Output:

Unclosed: Connection#1
Unclosed: ResultSet#2 from PreparedStatement#1 (SELECT f1,f2 fROM t1 
WHERE f1 > ?) from Connection#1
Unclosed: Statement#1 from Connection#1
Unclosed: PreparedStatement#1 (SELECT f1,f2 fROM t1 WHERE f1 > ?) from 
Connection#1
Unclosed: ResultSet#1 (SELECT f1,f2 fROM t1) from Statement#1 from 
Connection#1

The "magic" sauce:

import java.io.PrintStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;

public class Reveal {
     public static interface TrackableResource {
         public String getId() throws SQLException;
     }
     private static Set<TrackableResource> reslst = new 
HashSet<TrackableResource>();
     public static class ResultSetWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private ResultSet rs;
         private String parent;
         private String sql;
         public ResultSetWrapper(ResultSet rs, String parent) {
             this.rs = rs;
             this.parent = parent;
             this.sql = null;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public ResultSetWrapper(ResultSet rs, String parent, String sql) {
             this.rs = rs;
             this.parent = parent;
             this.sql = sql;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 reslst.remove(this);
                 return method.invoke(rs, args);
             } else {
                 return method.invoke(rs, args);
             }
         }
         public String getId() throws SQLException {
             if(sql == null) {
                 return "ResultSet#" + num + " from " + parent;
             } else {
                 return "ResultSet#" + num + " (" + sql + ") from " + 
parent;
             }
         }
     }
     public static class PreparedStatementWrapper implements 
InvocationHandler, TrackableResource {
         private static int count = 0;
         private int num;
         private Statement stmt;
         private String parent;
         private String sql;
         public PreparedStatementWrapper(Statement stmt, String parent, 
String sql) {
             this.stmt = stmt;
             this.parent = parent;
             this.sql = sql;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 reslst.remove(this);
                 return method.invoke(stmt, args);
             } else if(method.getName().equals("executeQuery")) {
                 return 
(ResultSet)Proxy.newProxyInstance(getClass().getClassLoader(), new 
Class<?>[] { ResultSet.class },
                                                          new 
ResultSetWrapper((ResultSet)method.invoke(stmt, args), getId()));
             } else {
                 return method.invoke(stmt, args);
             }
         }
         public String getId() throws SQLException {
             return "PreparedStatement#" + num + " (" + sql + ") from " 
+ parent;
         }
     }
     public static class StatementWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private Statement stmt;
         private String parent;
         public StatementWrapper(Statement stmt, String parent) {
             this.stmt = stmt;
             this.parent = parent;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 reslst.remove(this);
                 return method.invoke(stmt, args);
             } else if(method.getName().equals("executeQuery")) {
                 return 
(ResultSet)Proxy.newProxyInstance(getClass().getClassLoader(), new 
Class<?>[] { ResultSet.class },
                                                          new 
ResultSetWrapper((ResultSet)method.invoke(stmt, args), getId(), 
(String)args[0]));
             } else {
                 return method.invoke(stmt, args);
             }
         }
         public String getId() throws SQLException {
             return "Statement#" + num + " from " + parent;
         }
     }
     public static class ConnectionWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private Connection con;
         public ConnectionWrapper(Connection con) {
             this.con = con;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 reslst.remove(this);
                 return method.invoke(con, args);
             } else if(method.getName().equals("createStatement")) {
                 return 
(Statement)Proxy.newProxyInstance(con.getClass().getClassLoader(), new 
Class<?>[] { Statement.class },
                                                          new 
StatementWrapper((Statement)method.invoke(con, args), getId()));
             } else if(method.getName().equals("prepareStatement")) {
                 return 
(PreparedStatement)Proxy.newProxyInstance(con.getClass().getClassLoader(), 
new Class<?>[] { PreparedStatement.class },
                                                                  new 
PreparedStatementWrapper((PreparedStatement)method.invoke(con, args), 
getId(), (String)args[0]));
             } else {
                 return method.invoke(con, args);
             }
         }
         public String getId() throws SQLException {
             return "Connection#" + num;
         }
     }
     public static Connection wrap(Connection con) {
         return 
(Connection)Proxy.newProxyInstance(con.getClass().getClassLoader(), new 
Class<?>[] { Connection.class },
                                                   new 
ConnectionWrapper(con));
     }
     public static void dumpOpen(PrintStream ps) throws SQLException {
         for(TrackableResource obj : reslst.toArray(new 
TrackableResource[0])) {
             System.out.println("Unclosed: " + obj.getId());
         }
     }
}

Arne

[toc] | [prev] | [next] | [standalone]


#37122

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-09 23:03 -0400
Message-ID<omgieb$ocl$1@gioia.aioe.org>
In reply to#37121
On 8/9/2017 8:53 PM, Arne Vajhøj wrote:
> The "magic" sauce:

> public class Reveal {

Well magic or not - it did have some bad concurrency
problem as I did not get all the synchronized in.

New version below.

Arne

import java.io.PrintStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;

public class Reveal {
     public static interface TrackableResource {
         public String getId() throws SQLException;
     }
     private static Set<TrackableResource> reslst = new 
HashSet<TrackableResource>();
     public static class ResultSetWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private ResultSet rs;
         private String parent;
         private String sql;
         public ResultSetWrapper(ResultSet rs, String parent) {
             this.rs = rs;
             this.parent = parent;
             this.sql = null;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public ResultSetWrapper(ResultSet rs, String parent, String sql) {
             this.rs = rs;
             this.parent = parent;
             this.sql = sql;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 synchronized(reslst) {
                     reslst.remove(this);
                 }
                 return method.invoke(rs, args);
             } else {
                 return method.invoke(rs, args);
             }
         }
         public String getId() throws SQLException {
             if(sql == null) {
                 return "ResultSet#" + num + " from " + parent;
             } else {
                 return "ResultSet#" + num + " (" + sql + ") from " + 
parent;
             }
         }
     }
     public static class PreparedStatementWrapper implements 
InvocationHandler, TrackableResource {
         private static int count = 0;
         private int num;
         private Statement stmt;
         private String parent;
         private String sql;
         public PreparedStatementWrapper(Statement stmt, String parent, 
String sql) {
             this.stmt = stmt;
             this.parent = parent;
             this.sql = sql;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 synchronized(reslst) {
                     reslst.remove(this);
                 }
                 return method.invoke(stmt, args);
             } else if(method.getName().equals("executeQuery")) {
                 return 
(ResultSet)Proxy.newProxyInstance(getClass().getClassLoader(), new 
Class<?>[] { ResultSet.class },
                                                          new 
ResultSetWrapper((ResultSet)method.invoke(stmt, args), getId()));
             } else {
                 return method.invoke(stmt, args);
             }
         }
         public String getId() throws SQLException {
             return "PreparedStatement#" + num + " (" + sql + ") from " 
+ parent;
         }
     }
     public static class StatementWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private Statement stmt;
         private String parent;
         public StatementWrapper(Statement stmt, String parent) {
             this.stmt = stmt;
             this.parent = parent;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 synchronized(reslst) {
                     reslst.remove(this);
                 }
                 return method.invoke(stmt, args);
             } else if(method.getName().equals("executeQuery")) {
                 return 
(ResultSet)Proxy.newProxyInstance(getClass().getClassLoader(), new 
Class<?>[] { ResultSet.class },
                                                          new 
ResultSetWrapper((ResultSet)method.invoke(stmt, args), getId(), 
(String)args[0]));
             } else {
                 return method.invoke(stmt, args);
             }
         }
         public String getId() throws SQLException {
             return "Statement#" + num + " from " + parent;
         }
     }
     public static class ConnectionWrapper implements InvocationHandler, 
TrackableResource {
         private static int count = 0;
         private int num;
         private Connection con;
         public ConnectionWrapper(Connection con) {
             this.con = con;
             synchronized(reslst) {
                 count++;
                 num = count;
                 reslst.add(this);
             }
         }
         public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
             if(method.getName().equals("close")) {
                 synchronized(reslst) {
                     reslst.remove(this);
                 }
                 return method.invoke(con, args);
             } else if(method.getName().equals("createStatement")) {
                 return 
(Statement)Proxy.newProxyInstance(con.getClass().getClassLoader(), new 
Class<?>[] { Statement.class },
                                                          new 
StatementWrapper((Statement)method.invoke(con, args), getId()));
             } else if(method.getName().equals("prepareStatement")) {
                 return 
(PreparedStatement)Proxy.newProxyInstance(con.getClass().getClassLoader(), 
new Class<?>[] { PreparedStatement.class },
                                                                  new 
PreparedStatementWrapper((PreparedStatement)method.invoke(con, args), 
getId(), (String)args[0]));
             } else {
                 return method.invoke(con, args);
             }
         }
         public String getId() throws SQLException {
             return "Connection#" + num;
         }
     }
     public static Connection wrap(Connection con) {
         return 
(Connection)Proxy.newProxyInstance(con.getClass().getClassLoader(), new 
Class<?>[] { Connection.class },
                                                   new 
ConnectionWrapper(con));
     }
     public static void dumpOpen(PrintStream ps) throws SQLException {
         synchronized(reslst) {
             for(TrackableResource obj : reslst.toArray(new 
TrackableResource[0])) {
                 System.out.println("Unclosed: " + obj.getId());
             }
         }
     }
}

[toc] | [prev] | [next] | [standalone]


#37094

FromArne Vajhøj <arne@vajhoej.dk>
Date2017-08-08 21:48 -0400
Message-ID<omdplj$dne$2@gioia.aioe.org>
In reply to#37092
On 8/8/2017 9:25 PM, Arne Vajhøj wrote:
> As already mentioned by somebody else then executing multiple queries

in parallel

> on the same connection and statement is not safe.

Arne

[toc] | [prev] | [next] | [standalone]


#37103

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 07:24 +0200
Message-ID<87o9rpuxdj.fsf@munus.decebal.nl>
In reply to#37092
Arne Vajhøj <arne@vajhoej.dk> writes:

>> I thought that I could rewrite it to:
>>      private static void statistics() {
>>          try (Statement stmt     = conn.createStatement();
>>               ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>>               ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>>               ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
>
> As already mentioned by somebody else then executing multiple queries
> on the same connection and statement is not safe.
>
> And even if you modified the code to work on different connections and
> statements, then it would sort of violate good database programming
> practice by opening more stuff and keeping stuff open longer than
> needed.
>
> It would also require all readers of your code to know that close
> is called in reverse order for the code to look good in their eyes.
>
> Bottom line: bad!

I made it work, but that is a big no-no?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37095

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 06:26 +0200
Message-ID<87lgmtwels.fsf@munus.decebal.nl>
In reply to#37077
Cecil Westerhof <Cecil@decebal.nl> writes:

> I thought that I could rewrite it to:
>     private static void statistics() {
>         try (Statement stmt     = conn.createStatement();
>              ResultSet rsTotal  = stmt.executeQuery(COUNT_TOTAL_PROV);
>              ResultSet rsUnused = stmt.executeQuery(COUNT_UNUSED_PROV);
>              ResultSet rsUsed   = stmt.executeQuery(COUNT_USED_PROV)) {
>             int    count;
>             String format;
>
>             count  = rsTotal.getInt("no");
>             format = String.format("There are %%,%dd %%6s proverbs.%%n", String.format("%,d", count).length());
>             System.out.printf(format, count, "total");
>             count  = rsUnused.getInt("no");
>             if (count != 0) {
>                 System.out.printf(format, count, "unused");
>             }
>             count  = rsUsed.getInt("no");
>             System.out.printf(format, count, "used");
>         } catch (SQLException e) {
>             System.err.printf("Error in statistics\n");
>             e.printStackTrace();
>             fatalError("");
>         }
>     }
>
> That would be a little better I think, but when there are a lot of
> queries to be done, you need to define a lot of extra result-sets.
>
> But there is a problem with that. If I do that, all three result-sets
> have the same query: the last one.
> What is the reason for this? I am using SQLite3.

I do not know enough about the JDBC. When looking at:
    https://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html

It clearly states that you normally only can have one current
result-set pro statement. It says there:
    All execution methods in the Statement interface implicitly close
    a current ResultSet object of the statement if an open one exists.

But that is clearly not true, because the other ones still work, but
are replaced with the other one.

The solution is to have a statement pro result-set, but than this
statement is only necessary for getting the result-set. So I rewrote
statistics to:
    private static void statistics() {
        try (ResultSet rsTotal  = executeQuery(COUNT_TOTAL_PROV);
             ResultSet rsUnused = executeQuery(COUNT_UNUSED_PROV);
             ResultSet rsUsed   = executeQuery(COUNT_USED_PROV)) {
            int    count;
            String format;

            count  = rsTotal.getInt("no");
            format = String.format("There are %%,%dd %%-6s proverbs.%%n",
                                   String.format("%,d", count).length());
            System.out.printf(format, count, "total");
            count  = rsUnused.getInt("no");
            if (count != 0) {
                System.out.printf(format, count, "unused");
            }
            count  = rsUsed.getInt("no");
            System.out.printf(format, count, "used");
        } catch (SQLException e) {
            System.err.printf("Error in statistics\n");
            e.printStackTrace();
            fatalError("");
        }
    }

And wrote the function executeQuery to make the code a little more
compact:
    private static ResultSet executeQuery(String query) throws SQLException {
        return conn.createStatement().executeQuery(query);
    }

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37105

FromCecil Westerhof <Cecil@decebal.nl>
Date2017-08-09 08:30 +0200
Message-ID<87efsluuas.fsf@munus.decebal.nl>
In reply to#37095
Cecil Westerhof <Cecil@decebal.nl> writes:

> The solution is to have a statement pro result-set, but than this
> statement is only necessary for getting the result-set. So I rewrote
> statistics to:
>     private static void statistics() {
>         try (ResultSet rsTotal  = executeQuery(COUNT_TOTAL_PROV);
>              ResultSet rsUnused = executeQuery(COUNT_UNUSED_PROV);
>              ResultSet rsUsed   = executeQuery(COUNT_USED_PROV)) {
>             int    count;
>             String format;
>
>             count  = rsTotal.getInt("no");
>             format = String.format("There are %%,%dd %%-6s proverbs.%%n",
>                                    String.format("%,d", count).length());
>             System.out.printf(format, count, "total");
>             count  = rsUnused.getInt("no");
>             if (count != 0) {
>                 System.out.printf(format, count, "unused");
>             }
>             count  = rsUsed.getInt("no");
>             System.out.printf(format, count, "used");
>         } catch (SQLException e) {
>             System.err.printf("Error in statistics\n");
>             e.printStackTrace();
>             fatalError("");
>         }
>     }
>
> And wrote the function executeQuery to make the code a little more
> compact:
>     private static ResultSet executeQuery(String query) throws SQLException {
>         return conn.createStatement().executeQuery(query);
>     }

This is a very simple case: I only retrieve a count. So I rewrote it
to:
    private static void statistics() {
        try  {
            int    count;
            String format;

            count  = getCount(COUNT_TOTAL_PROV);
            format = String.format("There are %%,%dd %%-6s proverbs.%%n",
                                   String.format("%,d", count).length());
            System.out.printf(format, count, "total");
            count  = getCount(COUNT_UNUSED_PROV);
            if (count != 0) {
                System.out.printf(format, count, "unused");
            }
            count  = getCount(COUNT_USED_PROV);
            System.out.printf(format, count, "used");
        } catch (SQLException e) {
            System.err.printf("Error in statistics%n");
            e.printStackTrace();
            fatalError("");
        }
    }

And I defined a function getCount:
    private static int getCount(String query) throws SQLException {
        int count;

        try (ResultSet rsCount  = executeQuery(query)) {
            count = rsCount.getInt("count");
        }
        return count;
    }

So in this case there are not multiple ResultSet and implicit
Statement.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#37107

FromAndreas Leitgeb <avl@logic.at>
Date2017-08-09 09:40 +0000
Message-ID<slrnoolmbl.o2q.avl@logic.at>
In reply to#37095
Cecil Westerhof <Cecil@decebal.nl> wrote:
>     private static void statistics() {
>         try (ResultSet rsTotal  = executeQuery(COUNT_TOTAL_PROV);
>              ResultSet rsUnused = executeQuery(COUNT_UNUSED_PROV);
>              ResultSet rsUsed   = executeQuery(COUNT_USED_PROV)) {

and

>     private static ResultSet executeQuery(String query) throws SQLException {
>         return conn.createStatement().executeQuery(query);
>     }

So, if one of the queries fails, what will happen to the statements 
created so far?

Or, rather, what will *not* happen to them?

>             format = String.format("There are %%,%dd %%-6s proverbs.%%n",
>                                    String.format("%,d", count).length());
>             System.out.printf(format, count, "total");

What's the point of determining the length of e.g. "1,234,567" just to
set it as the length for a "%,d", which would obviously produce exactly
that length, anyway?

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.java.programmer


csiph-web