Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #37077 > unrolled thread
| Started by | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| First post | 2017-08-08 13:26 +0200 |
| Last post | 2017-08-09 06:39 +0200 |
| Articles | 20 on this page of 30 — 5 participants |
Back to article view | Back to comp.lang.java.programmer
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 →
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-08-08 13:26 +0200 |
| Subject | Is 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]
| From | Martin Gregorie <martin@address-in-sig.invalid> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Patrick Roemer <sangamon@netcologne.de> |
|---|---|
| Date | 2017-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-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]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2017-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]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-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