/**
   * Actually obtain a JDBC Connection from the given DataSource. Same as {@link #getConnection},
   * but throwing the original SQLException.
   *
   * <p>Is aware of a corresponding Connection bound to the current thread, for example when using
   * {@link DataSourceTransactionManager}. Will bind a Connection to the thread if transaction
   * synchronization is active (e.g. if in a JTA transaction).
   *
   * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
   *
   * @param dataSource the DataSource to obtain Connections from
   * @return a JDBC Connection from the given DataSource
   * @throws SQLException if thrown by JDBC methods
   * @see #doReleaseConnection
   */
  public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    Assert.notNull(dataSource, "No DataSource specified");

    ConnectionHolder conHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null
        && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
      conHolder.requested();
      if (!conHolder.hasConnection()) {
        logger.debug("Fetching resumed JDBC Connection from DataSource");
        conHolder.setConnection(dataSource.getConnection());
      }
      return conHolder.getConnection();
    }
    // Else we either got no holder or an empty thread-bound holder here.

    logger.debug("Fetching JDBC Connection from DataSource");
    Connection con = dataSource.getConnection();

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      logger.debug("Registering transaction synchronization for JDBC Connection");
      // Use same Connection for further JDBC actions within the transaction.
      // Thread-bound object will get removed by synchronization at transaction completion.
      ConnectionHolder holderToUse = conHolder;
      if (holderToUse == null) {
        holderToUse = new ConnectionHolder(con);
      } else {
        holderToUse.setConnection(con);
      }
      holderToUse.requested();
      TransactionSynchronizationManager.registerSynchronization(
          new ConnectionSynchronization(holderToUse, dataSource));
      holderToUse.setSynchronizedWithTransaction(true);
      if (holderToUse != conHolder) {
        TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
      }
    }

    return con;
  }