Path: csiph.com!news.mixmin.net!newsreader4.netcologne.de!news.netcologne.de!.POSTED.2001-4dd3-a0ab-0-ec80-db61-7728-b97f.ipv6dyn.netcologne.de!not-for-mail From: Patrick Roemer Newsgroups: comp.lang.java.programmer Subject: Re: Does this make sense? Date: Fri, 5 Apr 2019 17:43:32 +0200 Organization: news.netcologne.de Distribution: world Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Injection-Date: Fri, 5 Apr 2019 15:43:32 -0000 (UTC) Injection-Info: newsreader4.netcologne.de; posting-host="2001-4dd3-a0ab-0-ec80-db61-7728-b97f.ipv6dyn.netcologne.de:2001:4dd3:a0ab:0:ec80:db61:7728:b97f"; logging-data="21749"; mail-complaints-to="abuse@netcologne.de" User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.24) Gecko/20100411 Thunderbird/2.0.0.24 Mnenhy/0.7.6.0 X-Mozilla-News-Host: news://news.netcologne.de In-Reply-To: Content-Language: en-US Xref: csiph.com comp.lang.java.programmer:38873 Responding to Eric Douglas: > public static String testMethod(final String db_connect_string, final String db_userid, final String db_password, final String dbDriver, final String queryText) throws ClassNotFoundException { > Class.forName(dbDriver); > Connection conn = null; > PreparedStatement ps = null; > ResultSet rs = null; > try { > conn = DriverManager.getConnection(db_connect_string, db_userid, db_password); > ps = conn.prepareStatement(queryText, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); > rs = ps.getResultSet(); > } catch (final SQLException e) { > e.printStackTrace(); > try { > if (ps != null) { > ps.close(); > } > if (conn != null) { > conn.close(); > } > conn = DriverManager.getConnection("alternate connect string", db_userid, db_password); > ps = conn.prepareStatement(queryText, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); > rs = ps.getResultSet(); > } catch (final SQLException e1) { > e1.printStackTrace(); > } > } > try { > while (rs.next()) { > System.out.println(rs.getRow()); > } > } catch (final SQLException e1) { > e1.printStackTrace(); > } finally { > try { > rs.close(); > } catch (final SQLException e) { > e.printStackTrace(); > throw new Error("SQL issue"); > } > } > if (ps != null) { > try { > ps.close(); > } catch (final SQLException e) { > e.printStackTrace(); > if (conn != null) { > try { > conn.close(); > } catch (final SQLException e1) { > e1.printStackTrace(); > throw new Error("SQL issue"); > } > } > throw new Error("SQL issue"); > } > } > if (conn != null) { > try { > conn.close(); > } catch (final SQLException e) { > e.printStackTrace(); > throw new Error("SQL issue"); > } > } > return null; > } So you want to open a DB connection, run a prepared statement and obtain a result set. If any of these steps fails along the way, you want to retry these steps against a different DB URL. Once you have the result set, you want to run code against it and *not* retry upon failure. And of course you want to close all resources, no matter what code path has been taken. Does that capture the intent? This feels somewhat odd. I can imagine retrying against the mirror when the primary DB isn't reachable. But if the statement/result fetching fails on a live primary, why should I hope for better results against the mirror? Anyway, just going with it, I'd try to extract exception handling responsibilities to reusable abstractions that can also be tested standalone. Assume you implement the following: @FunctionalInterface public interface CheckedFunction { O apply(I input) throws E; } @FunctionalInterface public interface CheckedSupplier { O get() throws E; } public static O tryAlternatives( CheckedFunction op, I firstInput, I... moreInputs ) throws E { ... } public class CumulativeResource implements AutoCloseable { public final T resource; public interface CumulativeResourceBuilder { CumulativeResourceBuilder cumulate(CheckedFunction builder); CumulativeResource build() throws Exception; } public static CumulativeResourceBuilder from(CheckedSupplier factory) { ... } } Then your actual code might become this: CumulativeResource fetchResult(String dbUrl) throws Exception { return CumulativeResource .from(() -> DriverManager.getConnection(dbUrl, user, password)) .cumulate(c -> c.prepareStatement( query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY ) ) .cumulate(PreparedStatement::executeQuery) .build(); } void runQuery() throws Exception { try(CumulativeResource rsRes = tryAlternatives(this::fetchResult, firstDbUrl, secondDbUrl)) { ResultSet rs = rsRes.resource; while (rs.next()) { System.out.println(rs.getRow()); } } } Best regards, Patrick