public static PreparedStatement prepareWithRetry(Connection conn, String stmt,
      long waitWindow, int maxRetries) throws SQLException {

    // retry with # of maxRetries before throwing exception
    for (int failures = 0; ; failures++) {
      try {
        return conn.prepareStatement(stmt);
      } catch (SQLTransientException e) {
        if (failures >= maxRetries) {
          LOG.error("Error preparing JDBC Statement {}", stmt, e);
          throw e;
        }
        long waitTime = Utilities.getRandomWaitTime(waitWindow, failures,
            ThreadLocalRandom.current());
        try {
          Thread.sleep(waitTime);
        } catch (InterruptedException e1) {
        }
      } catch (SQLException e) {
        // just throw other types (SQLNonTransientException / SQLRecoverableException)
        throw e;
      }
    }
  }
Retry preparing a SQL statement with random backoff (same as the one implemented in HDFS-767).
This function only retries when the SQL query throws a SQLTransientException (which
might be able to succeed with a simple retry). It doesn't retry when the exception
is a SQLRecoverableException or SQLNonTransientException. For SQLRecoverableException
the caller needs to reconnect to the database and restart the whole transaction.

@param conn a JDBC connection.
@param stmt the SQL statement to be prepared.
@param waitWindow  The base time window (in milliseconds) before the next retry.
see {@link #getRandomWaitTime} for details.
@param maxRetries the maximum # of retries when getting a SQLTransientException.
@throws SQLException throws SQLRecoverableException or SQLNonTransientException the
first time it is caught, or SQLTransientException when the maxRetries has reached.
ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java