Guide de CockroachDB en Java

Guide de CockroachDB en Java

1. introduction

Ce tutoriel est un guide d'introduction à l'utilisation de CockroachDB avec Java.

Nous expliquerons les fonctionnalités clés, comment configurer un cluster local et comment le surveiller,along with a practical guide on how we can use Java to connect and interact with the server.

Commençons par définir de quoi il s'agit.

2. CafardDB

CockroachDB est une base de données SQL distribuée construite sur un magasin transactionnel et cohérent de valeurs-clés.

Écrit en Go et complètement open source,its primary design goals are the support for ACID transactions, horizontal scalability, and survivability. Avec ces objectifs de conception, il vise à tout tolérer, d'une panne de disque unique à un crash de centre de données complet avec une interruption de latence minimale et sans intervention manuelle.

Par conséquent,CockroachDB can be considered a well-suited solution for applications that require reliable, available, and correct data regardless of scale. Cependant, ce n’est pas le premier choix lorsque des lectures et des écritures à très faible latence sont essentielles.

2.1. Principales caractéristiques

Continuons à explorer certains des aspects clés de CockroachDB:

  • SQL API and PostgreSQL compatibility - pour structurer, manipuler et interroger des données

  • ACID transactions - prend en charge les transactions distribuées et offre une forte cohérence

  • Cloud-ready - conçu pour fonctionner dans le cloud ou sur une solution sur site offrant une migration facile entre différents fournisseurs de cloud sans aucune interruption de service

  • Scales horizontally - l'ajout de capacité est aussi simple que de pointer un nouveau nœud vers le cluster en cours d'exécution avec une surcharge d'opérateur minimale

  • Replication - réplique les données pour la disponibilité et garantit la cohérence entre les réplicas

  • Automated repair - continue de manière transparente tant que la majorité des réplicas restent disponibles pour les échecs à court terme tandis que, pour les échecs à long terme, rééquilibre automatiquement les réplicas à partir des nœuds manquants, en utilisant les réplicas non affectés comme sources

3. Configurer CockroachDB

Une fois que nous avonsinstalled CockroachDB, nous pouvons démarrer le premier nœud de notre cluster local:

cockroach start --insecure --host=localhost;

À des fins de démonstration, nous utilisons l'attributinsecure, ce qui rend la communication non chiffrée, sans qu'il soit nécessaire de spécifier l'emplacement des certificats.

À ce stade, notre cluster local est opérationnel. Avec un seul nœud, nous pouvons déjà nous y connecter et opérer maisto better take advantages of CockroachDB’s automatic replication, rebalancing, and fault tolerance, we’ll add two more nodes:

cockroach start --insecure --store=node2 \
  --host=localhost --port=26258 --http-port=8081 \
  --join=localhost:26257;

cockroach start --insecure --store=node3 \
  --host=localhost --port=26259 --http-port=8082 \
  --join=localhost:26257;

Pour les deux nœuds supplémentaires, nous avons utilisé l'indicateurjoin pour connecter les nouveaux nœuds au cluster, en spécifiant l'adresse et le port du premier nœud, dans notre cas localhost: 26257. Each node on the local cluster requires unique store, port, and http-port values.

Lors de la configuration d'un cluster distribué de CockroachDB, chaque nœud sera sur une machine différente, et ainsi la spécification desport,store ethttp-port peut être évitée puisque les valeurs par défaut suffisent. De plus, l'adresse IP réelle du premier nœud doit être utilisée lors de la jonction des nœuds supplémentaires au cluster.

3.1. Configuration de la base de données et de l'utilisateur

Une fois notre cluster opérationnel, via la console SQL fournie avec CockroachDB, nous devons créer notre base de données et un utilisateur.

Tout d'abord, démarrons la console SQL:

cockroach sql --insecure;

Maintenant, créons notre base de donnéestestdb, créons un utilisateur et ajoutons des subventions à l'utilisateur afin de pouvoir effectuer des opérations CRUD:

CREATE DATABASE testdb;
CREATE USER user17 with password 'qwerty';
GRANT ALL ON DATABASE testdb TO user17;

Si nous voulons vérifier que la base de données a été créée correctement, nous pouvons répertorier toutes les bases de données créées dans le nœud actuel:

SHOW DATABASES;

Enfin, si nous voulons vérifier la fonctionnalité de réplication automatique de CockroachDB, nous pouvons vérifier sur l’un des deux autres nœuds si la base de données a été créée correctement. Pour ce faire, nous devons exprimer le drapeauport lorsque nous utilisons la console SQL:

cockroach sql --insecure --port=26258;

4. Surveillance des cafardsDB

Maintenant que nous avons démarré notre cluster local et créé la base de données,we can monitor them using the CockroachDB Admin UI:

image

Cette interface utilisateur d'administration, fournie dans un ensemble avec CockroachDB, est accessible àhttp://localhost:8080 dès que le cluster est opérationnel. En particulier,it provides details about cluster and database configuration, and helps us optimize cluster performance by monitoring metrics like:

  • Cluster Health - métriques essentielles sur la santé du cluster

  • Runtime Metrics - métriques sur le nombre de nœuds, le temps CPU et l'utilisation de la mémoire

  • SQL Performance - métriques sur les connexions SQL, les requêtes et les transactions

  • Replication Details - métriques sur la façon dont les données sont répliquées dans le cluster

  • Node Details - détails des nœuds actifs, morts et hors service

  • Database Details - détails sur les bases de données système et utilisateur dans le cluster

5. Project Setup

Compte tenu de notre cluster local en cours d'exécution de CockroachDB, afin de pouvoir s'y connecter, nous devons ajouter unadditional dependency à notrepom.xml:


    org.postgresql
    postgresql
    42.1.4

Ou, pour un projet Gradle:

compile 'org.postgresql:postgresql:42.1.4'

6. Utilisation de CockroachDB

Maintenant que nous savons avec quoi nous travaillons et que tout est correctement configuré, commençons à l'utiliser.

Grâce à la compatibilité PostgreSQL,it’s either possible to connect directly with JDBC or using an ORM, such as Hibernate (au moment de la rédaction (janvier 2018) les deux pilotes ont été suffisamment testés pour réclamer le support debeta-level selon les développeurs). Dans notre cas, nous utiliserons JDBC pour interagir avec la base de données.

Pour plus de simplicité, nous allons suivre les opérations CRUD de base car elles sont les meilleures pour commencer.

Commençons par vous connecter à la base de données.

6.1. Connexion à CockroachDB

Pour ouvrir une connexion avec la base de données, nous pouvons utiliser la méthodegetConnection() de la classeDriverManager. Cette méthode nécessite un paramètre d'URL de connexionString, un nom d'utilisateur et un mot de passe:

Connection con = DriverManager.getConnection(
  "jdbc:postgresql://localhost:26257/testdb", "user17", "qwerty"
);

6.2. Créer une table

Avec une connexion fonctionnelle, nous pouvons commencer à créer la tablearticles que nous allons utiliser pour toutes les opérations CRUD:

String TABLE_NAME = "articles";
StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS ")
  .append(TABLE_NAME)
  .append("(id uuid PRIMARY KEY, ")
  .append("title string,")
  .append("author string)");

String query = sb.toString();
Statement stmt = connection.createStatement();
stmt.execute(query);

Si nous voulons vérifier que la table a été correctement créée, nous pouvons utiliser la commandeSHOW TABLES:

PreparedStatement preparedStatement = con.prepareStatement("SHOW TABLES");
ResultSet resultSet = preparedStatement.executeQuery();
List tables = new ArrayList<>();
while (resultSet.next()) {
    tables.add(resultSet.getString("Table"));
}

assertTrue(tables.stream().anyMatch(t -> t.equals(TABLE_NAME)));

Voyons comment il est possible de modifier le tableau qui vient d'être créé.

6.3. Modification d'une table

Si nous avons manqué des colonnes lors de la création de la table ou parce que nous en avions besoin plus tard, nous pouvons facilement les ajouter:

StringBuilder sb = new StringBuilder("ALTER TABLE ").append(TABLE_NAME)
  .append(" ADD ")
  .append(columnName)
  .append(" ")
  .append(columnType);

String query = sb.toString();
Statement stmt = connection.createStatement();
stmt.execute(query);

Une fois que nous avons modifié la table, nous pouvons vérifier si la nouvelle colonne a été ajoutée à l'aide de la commandeSHOW COLUMNS FROM:

String query = "SHOW COLUMNS FROM " + TABLE_NAME;
PreparedStatement preparedStatement = con.prepareStatement(query);
ResultSet resultSet = preparedStatement.executeQuery();
List columns = new ArrayList<>();
while (resultSet.next()) {
    columns.add(resultSet.getString("Field"));
}

assertTrue(columns.stream().anyMatch(c -> c.equals(columnName)));

6.4. Supprimer une table

Lorsque vous travaillez avec des tables, nous avons parfois besoin de les supprimer, ce qui peut être facilement réalisé avec quelques lignes de code:

StringBuilder sb = new StringBuilder("DROP TABLE IF EXISTS ")
  .append(TABLE_NAME);

String query = sb.toString();
Statement stmt = connection.createStatement();
stmt.execute(query);

6.5. Insertion de données

Une fois que nous avons effacé les opérations pouvant être effectuées sur une table, nous pouvons maintenant commencer à travailler avec des données. Nous pouvons commencer à définir la classeArticle:

public class Article {

    private UUID id;
    private String title;
    private String author;

    // standard constructor/getters/setters
}

Nous pouvons maintenant voir comment ajouter unArticle à notre tablearticles:

StringBuilder sb = new StringBuilder("INSERT INTO ").append(TABLE_NAME)
  .append("(id, title, author) ")
  .append("VALUES (?,?,?)");

String query = sb.toString();
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, article.getId().toString());
preparedStatement.setString(2, article.getTitle());
preparedStatement.setString(3, article.getAuthor());
preparedStatement.execute();

6.6. Lecture des données

Une fois que les données sont stockées dans une table, nous voulons les lire, ce qui peut être facilement réalisé:

StringBuilder sb = new StringBuilder("SELECT * FROM ")
  .append(TABLE_NAME);

String query = sb.toString();
PreparedStatement preparedStatement = connection.prepareStatement(query);
ResultSet rs = preparedStatement.executeQuery();

Cependant, si nous ne voulons pas lire toutes les données de la tablearticles mais seulement unArticle, nous pouvons simplement changer la façon dont nous construisons nosPreparedStatement:

StringBuilder sb = new StringBuilder("SELECT * FROM ").append(TABLE_NAME)
  .append(" WHERE title = ?");

String query = sb.toString();
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, title);
ResultSet rs = preparedStatement.executeQuery();

6.7. Suppression de données

Enfin, si nous voulons supprimer des données de notre table, nous pouvons supprimer un ensemble limité d'enregistrements à l'aide de la commande standardDELETE FROM:

StringBuilder sb = new StringBuilder("DELETE FROM ").append(TABLE_NAME)
  .append(" WHERE title = ?");

String query = sb.toString();
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, title);
preparedStatement.execute();

Ou nous pouvons supprimer tous les enregistrements, dans la table, avec la fonctionTRUNCATE:

StringBuilder sb = new StringBuilder("TRUNCATE TABLE ")
  .append(TABLE_NAME);

String query = sb.toString();
Statement stmt = connection.createStatement();
stmt.execute(query);

6.8. Traitement des transactions

Une fois connectée à la base de données, chaque instruction SQL individuelle est traitée par défaut comme une transaction et est automatiquement validée dès la fin de son exécution.

Toutefois, si nous souhaitons autoriser le regroupement de deux ou plusieurs instructions SQL dans une seule transaction, nous devons contrôler la transaction par programme.

Tout d'abord, nous devons désactiver le mode de validation automatique en définissant la propriétéautoCommit deConnection surfalse, puis utiliser les méthodescommit() etrollback() pour contrôler la transaction.

Voyons comment nous pouvons assurer la cohérence des données lors de plusieurs insertions:

try {
    con.setAutoCommit(false);

    UUID articleId = UUID.randomUUID();

    Article article = new Article(
      articleId, "Guide to CockroachDB in Java", "example"
    );
    articleRepository.insertArticle(article);

    article = new Article(
      articleId, "A Guide to MongoDB with Java", "example"
    );
    articleRepository.insertArticle(article); // Exception

    con.commit();
} catch (Exception e) {
    con.rollback();
} finally {
    con.setAutoCommit(true);
}

Dans ce cas, une exception a été levée, sur la deuxième insertion, pour la violation de la contrainte de clé primaire et par conséquent aucun article n'a été inséré dans la tablearticles.

7. Conclusion

Dans cet article, nous avons expliqué ce qu'est CockroachDB, comment configurer un cluster local simple et comment interagir avec ce dernier à partir de Java.

Le code source complet de cet article se trouve, comme toujours,over on Github.