Share via


Java-app om verbinding te maken en SQL-opdrachten uit te voeren in Azure Cosmos DB for PostgreSQL

VAN TOEPASSING OP: Azure Cosmos DB for PostgreSQL (mogelijk gemaakt door de Citus-database-extensie voor PostgreSQL)

In deze quickstart ziet u hoe u Java-code gebruikt om verbinding te maken met een cluster en hoe u SQL-instructies gebruikt om een tabel te maken. Vervolgens gaat u gegevens in de database invoegen, opvragen, bijwerken en verwijderen. Bij de stappen in dit artikel wordt ervan uitgegaan dat u bekend bent met Java-ontwikkeling en JDBC en dat u geen ervaring hebt met het werken met Azure Cosmos DB for PostgreSQL.

Het Java-project en de verbinding instellen

Maak een nieuw Java-project en een configuratiebestand om verbinding te maken met Azure Cosmos DB for PostgreSQL.

Een nieuw Java-project maken

Maak met behulp van uw favoriete IDE (Integrated Development Environment) een nieuw Java-project met groupId test en artifactId crud. Voeg in de hoofdmap van het project een pom.xml-bestand toe met de volgende inhoud. Dit bestand configureert Apache Maven voor het gebruik van Java 8 en een recent PostgreSQL-stuurprogramma voor Java.

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>test</groupId>
  <artifactId>crud</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>crud</name>
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <version>5.7.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.12</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
    <dependency>
      <groupId>com.zaxxer</groupId>
      <artifactId>HikariCP</artifactId>
      <version>5.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-params</artifactId>
      <version>5.7.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.0.0-M5</version>
      </plugin>
    </plugins>
  </build>
</project>

Verbinding met de database configureren

Maak in src/main/resources/ een bestand application.properties met de volgende inhoud. Vervang het cluster> door <uw clusternaam en vervang het wachtwoord> door <uw beheerderswachtwoord.

driver.class.name=org.postgresql.Driver
db.url=jdbc:postgresql://c-<cluster>.<uniqueID>.postgres.cosmos.azure.com:5432/citus?ssl=true&sslmode=require
db.username=citus
db.password=<password>

De ?ssl=true&sslmode=require tekenreeks in de db.url eigenschap vertelt het JDBC-stuurprogramma dat tls (Transport Layer Security) moet worden gebruikt bij het maken van verbinding met de database. Het is verplicht om TLS te gebruiken met Azure Cosmos DB for PostgreSQL en is een goede beveiligingspraktijk.

Tabellen maken

Configureer een databaseschema met gedistribueerde tabellen. Maak verbinding met de database om het schema en de tabellen te maken.

Het databaseschema genereren

Maak in src/main/resources/ een schema.sql-bestand met de volgende inhoud:

DROP TABLE IF EXISTS public.pharmacy;
CREATE TABLE  public.pharmacy(pharmacy_id integer,pharmacy_name text ,city text ,state text ,zip_code integer);
CREATE INDEX idx_pharmacy_id ON public.pharmacy(pharmacy_id);

Tabellen distribueren

Azure Cosmos DB for PostgreSQL biedt u de superkracht van het distribueren van tabellen over meerdere knooppunten voor schaalbaarheid. Met de onderstaande opdracht kunt u een tabel distribueren. Meer informatie over create_distributed_table en de distributiekolom vindt u hier.

Notitie

Als u tabellen distribueert, kunnen deze worden verdeeld over alle werkknooppunten die aan het cluster zijn toegevoegd.

Als u tabellen wilt distribueren, voegt u de volgende regel toe aan het bestand schema.sql dat u in de vorige sectie hebt gemaakt.

select create_distributed_table('public.pharmacy','pharmacy_id');

Verbinding maken met de database en het schema maken

Voeg vervolgens de Java-code toe die gebruikmaakt van JDBC om gegevens op te slaan en op te halen uit uw cluster. De code gebruikt de bestanden application.properties en schema.sql om verbinding te maken met het cluster en het schema te maken.

  1. Maak een DButil.java-bestand met de volgende code, die de DButil klasse bevat. De DBUtil klasse stelt een verbindingsgroep in met PostgreSQL met behulp van HikariCP. U gebruikt deze klasse om verbinding te maken met PostgreSQL en query's uit te voeren.

    Tip

    In de onderstaande voorbeeldcode wordt een verbindingsgroep gebruikt om verbindingen met PostgreSQL te maken en te beheren. Groepsgewijze verbindingen aan de toepassingszijde wordt sterk aanbevolen omdat:

    • Het zorgt ervoor dat de toepassing niet te veel verbindingen met de database genereert en zo wordt voorkomen dat de verbindingslimieten worden overschreden.
    • Het kan helpen de prestaties drastisch te verbeteren, zowel latentie als doorvoer. Het PostgreSQL-serverproces moet fork zijn om elke nieuwe verbinding te verwerken. Als u een verbinding opnieuw gebruikt, wordt deze overhead vermeden.
    //DButil.java
    package test.crud;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.sql.SQLException;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import com.zaxxer.hikari.HikariDataSource;
    
    public class DButil {
        private static final String DB_USERNAME = "db.username";
        private static final String DB_PASSWORD = "db.password";
        private static final String DB_URL = "db.url";
        private static final String DB_DRIVER_CLASS = "driver.class.name";
        private static Properties properties =  null;
        private static HikariDataSource datasource;
    
        static {
            try {
                properties = new Properties();
                properties.load(new FileInputStream("src/main/java/application.properties"));
    
                datasource = new HikariDataSource();
                datasource.setDriverClassName(properties.getProperty(DB_DRIVER_CLASS ));
                datasource.setJdbcUrl(properties.getProperty(DB_URL));
                datasource.setUsername(properties.getProperty(DB_USERNAME));
                datasource.setPassword(properties.getProperty(DB_PASSWORD));
                datasource.setMinimumIdle(100);
                datasource.setMaximumPoolSize(1000000000);
                datasource.setAutoCommit(true);
                datasource.setLoginTimeout(3);
            } catch (IOException | SQLException  e) {
                e.printStackTrace();
            }
        }
        public static DataSource getDataSource() {
            return datasource;
        }
    }
    
  2. Maak in src/main/java/ een bestand DemoApplication.java dat de volgende code bevat:

    package test.crud;
    import java.io.IOException;
    import java.sql.*;
    import java.util.*;
    import java.util.logging.Logger;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import org.postgresql.copy.CopyManager;
    import org.postgresql.core.BaseConnection;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.StringReader;
    
    public class DemoApplication {
    
        private static final Logger log;
    
        static {
            System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n");
            log =Logger.getLogger(DemoApplication.class.getName());
        }
        public static void main(String[] args)throws Exception
        {
            log.info("Connecting to the database");
            Connection connection = DButil.getDataSource().getConnection();
            System.out.println("The Connection Object is of Class: " + connection.getClass());
            log.info("Database connection test: " + connection.getCatalog());
            log.info("Creating table");
            log.info("Creating index");
            log.info("distributing table");
            Scanner scanner = new Scanner(DemoApplication.class.getClassLoader().getResourceAsStream("schema.sql"));
            Statement statement = connection.createStatement();
            while (scanner.hasNextLine()) {
                statement.execute(scanner.nextLine());
            }
            log.info("Closing database connection");
            connection.close();
        }
    
    }
    

    Notitie

    De database user en password referenties worden gebruikt bij het uitvoeren van DriverManager.getConnection(properties.getProperty("url"), properties);. De referenties worden opgeslagen in het bestand application.properties , dat wordt doorgegeven als een argument.

  3. U kunt nu deze main-klasse uitvoeren met uw favoriete tool:

    • Met behulp van uw IDE kunt u met de rechtermuisknop op de DemoApplication klasse klikken en deze uitvoeren.
    • Met Maven kunt u de toepassing uitvoeren door het volgende uit te voeren:
      mvn exec:java -Dexec.mainClass="com.example.demo.DemoApplication".

De toepassing moet verbinding maken met Azure Cosmos DB for PostgreSQL, een databaseschema maken en vervolgens de verbinding sluiten, zoals u zou moeten zien in de consolelogboeken:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Create database schema
[INFO   ] Closing database connection

Een domeinklasse maken

Maak een nieuwe Java-klasse Pharmacy, naast de klasse DemoApplication, en voeg de volgende code toe:

public class Pharmacy {
    private Integer pharmacy_id;
    private String pharmacy_name;
    private String city;
    private String state;
    private Integer zip_code;
    public Pharmacy() { }
    public Pharmacy(Integer pharmacy_id, String pharmacy_name, String city,String state,Integer zip_code)
    {
        this.pharmacy_id = pharmacy_id;
        this.pharmacy_name = pharmacy_name;
        this.city = city;
        this.state = state;
        this.zip_code = zip_code;
    }

    public Integer getpharmacy_id() {
        return pharmacy_id;
    }

    public void setpharmacy_id(Integer pharmacy_id) {
        this.pharmacy_id = pharmacy_id;
    }

    public String getpharmacy_name() {
        return pharmacy_name;
    }

    public void setpharmacy_name(String pharmacy_name) {
        this.pharmacy_name = pharmacy_name;
    }

    public String getcity() {
        return city;
    }

    public void setcity(String city) {
        this.city = city;
    }

    public String getstate() {
        return state;
    }

    public void setstate(String state) {
        this.state = state;
    }

    public Integer getzip_code() {
        return zip_code;
    }

    public void setzip_code(Integer zip_code) {
        this.zip_code = zip_code;
    }
    @Override
    public String toString() {
        return "TPharmacy{" +
               "pharmacy_id=" + pharmacy_id +
               ", pharmacy_name='" + pharmacy_name + '\'' +
               ", city='" + city + '\'' +
               ", state='" + state + '\'' +
               ", zip_code='" + zip_code + '\'' +
               '}';
    }
}

Deze klasse is een domeinmodel dat is toegewezen aan de tabel Pharmacy die u eerder hebt gemaakt tijdens het uitvoeren van het script schema.sql.

Gegevens invoegen

Voeg in het bestand DemoApplication.java na de main methode de volgende methode toe die gebruikmaakt van de SQL-instructie INSERT INTO om gegevens in te voegen in de database:

private static void insertData(Pharmacy todo, Connection connection) throws SQLException {
    log.info("Insert data");
    PreparedStatement insertStatement = connection
        .prepareStatement("INSERT INTO pharmacy (pharmacy_id,pharmacy_name,city,state,zip_code)  VALUES (?, ?, ?, ?, ?);");

    insertStatement.setInt(1, todo.getpharmacy_id());
    insertStatement.setString(2, todo.getpharmacy_name());
    insertStatement.setString(3, todo.getcity());
    insertStatement.setString(4, todo.getstate());
    insertStatement.setInt(5, todo.getzip_code());

    insertStatement.executeUpdate();
}

Voeg de twee volgende regels toe in de methode main:

Pharmacy todo = new Pharmacy(0,"Target","Sunnyvale","California",94001);
insertData(todo, connection);

Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Closing database connection

Gegevens lezen

Lees de gegevens die u eerder hebt ingevoegd om te controleren of uw code correct werkt.

Voeg in het bestand DemoApplication.java na de insertData methode de volgende methode toe die gebruikmaakt van de SQL-instructie SELECT om gegevens uit de database te lezen:

private static Pharmacy readData(Connection connection) throws SQLException {
    log.info("Read data");
    PreparedStatement readStatement = connection.prepareStatement("SELECT * FROM Pharmacy;");
    ResultSet resultSet = readStatement.executeQuery();
    if (!resultSet.next()) {
        log.info("There is no data in the database!");
        return null;
    }
    Pharmacy todo = new Pharmacy();
    todo.setpharmacy_id(resultSet.getInt("pharmacy_id"));
    todo.setpharmacy_name(resultSet.getString("pharmacy_name"));
    todo.setcity(resultSet.getString("city"));
    todo.setstate(resultSet.getString("state"));
    todo.setzip_code(resultSet.getInt("zip_code"));
    log.info("Data read from the database: " + todo.toString());
    return todo;
}

Voeg de volgende regel toe in de methode main:

todo = readData(connection);

Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO   ] Closing database connection

Gegevens bijwerken

Werk de gegevens bij die u eerder hebt ingevoegd.

Voeg in het bestand DemoApplication.java , na de readData methode, de volgende methode toe om gegevens in de database bij te werken met behulp van de SQL-instructie UPDATE:

private static void updateData(Pharmacy todo, Connection connection) throws SQLException {
    log.info("Update data");
    PreparedStatement updateStatement = connection
        .prepareStatement("UPDATE pharmacy SET city = ? WHERE pharmacy_id = ?;");

    updateStatement.setString(1, todo.getcity());

    updateStatement.setInt(2, todo.getpharmacy_id());
    updateStatement.executeUpdate();
    readData(connection);
}

Voeg de twee volgende regels toe in de methode main:

todo.setcity("Guntur");
updateData(todo, connection);

Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO   ] Closing database connection

Gegevens verwijderen

Verwijder ten slotte de gegevens die u eerder hebt ingevoegd. Voeg in het bestand DemoApplication.java , na de updateData methode, de volgende methode toe om gegevens in de database te verwijderen met behulp van de SQL-instructie DELETE:

private static void deleteData(Pharmacy todo, Connection connection) throws SQLException {
    log.info("Delete data");
    PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM pharmacy WHERE pharmacy_id = ?;");
    deleteStatement.setLong(1, todo.getpharmacy_id());
    deleteStatement.executeUpdate();
    readData(connection);
}

U kunt nu de volgende regel toevoegen in de hoofdmethode:

deleteData(todo, connection);

Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO   ] Delete data
[INFO   ] Read data
[INFO   ] There is no data in the database!
[INFO   ] Closing database connection

COPY-opdracht voor snelle opname

De opdracht COPY kan een enorme doorvoer opleveren tijdens het opnemen van gegevens in Azure Cosmos DB for PostgreSQL. Met de opdracht COPY kunnen gegevens worden opgenomen in bestanden of uit microbatches met gegevens in het geheugen voor realtime-opname.

COPY-opdracht voor het laden van gegevens uit een bestand

Met de volgende code worden gegevens uit een CSV-bestand gekopieerd naar een databasetabel. Voor het codevoorbeeld is het bestand pharmacies.csvvereist.

public static long
copyFromFile(Connection connection, String filePath, String tableName)
throws SQLException, IOException {
    long count = 0;
    FileInputStream fileInputStream = null;

    try {
        Connection unwrap = connection.unwrap(Connection.class);
        BaseConnection  connSec = (BaseConnection) unwrap;

        CopyManager copyManager = new CopyManager((BaseConnection) connSec);
        fileInputStream = new FileInputStream(filePath);
        count = copyManager.copyIn("COPY " + tableName + " FROM STDIN delimiter ',' csv", fileInputStream);
    } finally {
        if (fileInputStream != null) {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return count;
}

U kunt nu de volgende regel toevoegen in de hoofdmethode:

int c = (int) copyFromFile(connection,"C:\\Users\\pharmacies.csv", "pharmacy");
log.info("Copied "+ c +" rows using COPY command");

Als u de main klasse uitvoert, moet nu de volgende uitvoer worden geproduceerd:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO   ] Delete data
[INFO   ] Read data
[INFO   ] There is no data in the database!
[INFO ] Copied 5000 rows using COPY command
[INFO   ] Closing database connection

COPY-opdracht voor het laden van gegevens in het geheugen

Met de volgende code worden gegevens in het geheugen gekopieerd naar een tabel.

private static void inMemory(Connection connection) throws SQLException,IOException
    {
    log.info("Copying inmemory data into table");
            
    final List<String> rows = new ArrayList<>();
    rows.add("0,Target,Sunnyvale,California,94001");
    rows.add("1,Apollo,Guntur,Andhra,94003");
        
    final BaseConnection baseConnection = (BaseConnection) connection.unwrap(Connection.class);
    final CopyManager copyManager = new CopyManager(baseConnection);

    // COPY command can change based on the format of rows. This COPY command is for above rows.
    final String copyCommand = "COPY pharmacy FROM STDIN with csv";        
       
    try (final Reader reader = new StringReader(String.join("\n", rows))) {
        copyManager.copyIn(copyCommand, reader);
    }
}

U kunt nu de volgende regel toevoegen in de hoofdmethode:

inMemory(connection);

Als u nu de main-klasse uitvoert, zou dit de volgende uitvoer moeten opleveren:

[INFO   ] Loading application properties
[INFO   ] Connecting to the database
[INFO   ] Database connection test: citus
[INFO   ] Creating table
[INFO   ] Creating index
[INFO   ] distributing table
[INFO   ] Insert data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Sunnyvale', state='California', zip_code='94001'}
[INFO   ] Update data
[INFO   ] Read data
[INFO   ] Data read from the database: Pharmacy{pharmacy_id=0, pharmacy_name='Target', city='Guntur', state='California', zip_code='94001'}
[INFO   ] Delete data
[INFO   ] Read data
[INFO   ] There is no data in the database!
5000
[INFO   ] Copying in-memory data into table
[INFO   ] Closing database connection

App opnieuw proberen voor databaseaanvraagfouten

Het is soms mogelijk dat databaseaanvragen van uw toepassing mislukken. Dergelijke problemen kunnen zich voordoen in verschillende scenario's, zoals netwerkfouten tussen app en database, onjuist wachtwoord, enzovoort. Sommige problemen kunnen tijdelijk zijn en zichzelf binnen enkele seconden tot minuten oplossen. U kunt logica voor opnieuw proberen in uw app configureren om de tijdelijke fouten te verhelpen.

Het configureren van logica voor opnieuw proberen in uw app helpt de eindgebruikerservaring te verbeteren. Bij foutscenario's wachten gebruikers slechts iets langer totdat de toepassing aanvragen verwerkt, in plaats van fouten te ervaren.

In het onderstaande voorbeeld ziet u hoe u logica voor opnieuw proberen implementeert in uw app. Het voorbeeldcodefragment probeert elke 60 seconden (maximaal vijf keer) een databaseaanvraag uit te voeren totdat dit lukt. Het aantal en de frequentie van nieuwe pogingen kunnen worden geconfigureerd op basis van de behoeften van uw toepassing.

Vervang <in deze code het cluster> door uw clusternaam en <wachtwoord> door uw beheerderswachtwoord.

package test.crud;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.logging.Logger;
import com.zaxxer.hikari.HikariDataSource;

public class DemoApplication
{
    private static final Logger log;

    static
    {
        System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$-7s] %5$s %n");
        log = Logger.getLogger(DemoApplication.class.getName());
    }
    private static final String DB_USERNAME = "citus";
    private static final String DB_PASSWORD = "<password>";
    private static final String DB_URL = "jdbc:postgresql://c-<cluster>.<uniqueID>.postgres.cosmos.azure.com:5432/citus?sslmode=require";
    private static final String DB_DRIVER_CLASS = "org.postgresql.Driver";
    private static HikariDataSource datasource;

    private static String executeRetry(String sql, int retryCount) throws InterruptedException
    {
        Connection con = null;
        PreparedStatement pst = null;
        ResultSet rs = null;
        for (int i = 1; i <= retryCount; i++)
        {
            try
            {
                datasource = new HikariDataSource();
                datasource.setDriverClassName(DB_DRIVER_CLASS);
                datasource.setJdbcUrl(DB_URL);
                datasource.setUsername(DB_USERNAME);
                datasource.setPassword(DB_PASSWORD);
                datasource.setMinimumIdle(10);
                datasource.setMaximumPoolSize(1000);
                datasource.setAutoCommit(true);
                datasource.setLoginTimeout(3);
                log.info("Connecting to the database");
                con = datasource.getConnection();
                log.info("Connection established");
                log.info("Read data");
                pst = con.prepareStatement(sql);
                rs = pst.executeQuery();
                StringBuilder builder = new StringBuilder();
                int columnCount = rs.getMetaData().getColumnCount();
                while (rs.next())
                {
                    for (int j = 0; j < columnCount;)
                    {
                        builder.append(rs.getString(j + 1));
                        if (++j < columnCount)
                            builder.append(",");
                    }
                    builder.append("\r\n");
                }
                return builder.toString();
            }
            catch (Exception e)
            {
                Thread.sleep(60000);
                System.out.println(e.getMessage());
            }
        }
        return null;
    }

    public static void main(String[] args) throws Exception
    {
        String result = executeRetry("select 1", 5);
        System.out.print(result);
    }
}

Volgende stappen