Anleitung zu CockroachDB in Java

Anleitung zu CockroachDB in Java

1. Einführung

Dieses Tutorial ist eine Einführung in die Verwendung von CockroachDB mit Java.

Wir erklären die wichtigsten Funktionen, wie Sie einen lokalen Cluster konfigurieren und wie Sie ihn überwachen,along with a practical guide on how we can use Java to connect and interact with the server.

Beginnen wir damit, zunächst zu definieren, was es ist.

2. KakerlakeDB

CockroachDB ist eine verteilte SQL-Datenbank, die auf einem transaktionalen und konsistenten Schlüsselwertspeicher aufbaut.

Geschrieben in Go und vollständig Open Source,its primary design goals are the support for ACID transactions, horizontal scalability, and survivability. Mit diesen Entwurfszielen soll alles toleriert werden, vom Ausfall einer einzelnen Festplatte bis zum Absturz eines gesamten Rechenzentrums mit minimaler Unterbrechung der Latenz und ohne manuelles Eingreifen.

Infolgedessen istCockroachDB can be considered a well-suited solution for applications that require reliable, available, and correct data regardless of scale. jedoch nicht die erste Wahl, wenn Lese- und Schreibvorgänge mit sehr geringer Latenz kritisch sind.

2.1. Hauptmerkmale

Lassen Sie uns einige der wichtigsten Aspekte von CockroachDB weiter untersuchen:

  • SQL API and PostgreSQL compatibility - zum Strukturieren, Bearbeiten und Abfragen von Daten

  • ACID transactions - unterstützt verteilte Transaktionen und bietet starke Konsistenz

  • Cloud-ready - Entwickelt für die Ausführung in der Cloud oder in einer lokalen Lösung, die eine einfache Migration zwischen verschiedenen Cloud-Anbietern ohne Unterbrechung des Dienstes ermöglicht

  • Scales horizontally - Das Hinzufügen von Kapazität ist so einfach wie das Zeigen eines neuen Knotens auf den laufenden Cluster mit minimalem Bedieneraufwand

  • Replication - Repliziert Daten zur Verfügbarkeit und garantiert die Konsistenz zwischen Replikaten

  • Automated repair - Fahren Sie nahtlos fort, solange ein Großteil der Replikate für kurzfristige Fehler verfügbar bleibt, während bei längerfristigen Fehlern Replikate von den fehlenden Knoten automatisch neu gewichtet werden, wobei die nicht betroffenen Replikate als Quellen verwendet werden

3. CockroachDB konfigurieren

Nachdem wirinstalled CockroachDB haben, können wir den ersten Knoten unseres lokalen Clusters starten:

cockroach start --insecure --host=localhost;

Für Demozwecke verwenden wir das Attributinsecure, wodurch die Kommunikation unverschlüsselt wird, ohne dass der Speicherort des Zertifikats angegeben werden muss.

Zu diesem Zeitpunkt ist unser lokaler Cluster in Betrieb. Mit nur einem einzigen Knoten können wir bereits eine Verbindung herstellen und nurto better take advantages of CockroachDB’s automatic replication, rebalancing, and fault tolerance, we’ll add two more nodes betreiben:

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;

Für die beiden zusätzlichen Knoten haben wir das Flagjoin verwendet, um die neuen Knoten mit dem Cluster zu verbinden. Dabei haben wir die Adresse und den Port des ersten Knotens angegeben, in unserem Fall localhost: 26257. Each node on the local cluster requires unique store, port, and http-port values.

Bei der Konfiguration eines verteilten Clusters von CockroachDB befindet sich jeder Knoten auf einem anderen Computer. Daher kann die Angabe vonport,store undhttp-port vermieden werden, da die Standardwerte ausreichen. Außerdem sollte die tatsächliche IP des ersten Knotens verwendet werden, wenn die zusätzlichen Knoten dem Cluster hinzugefügt werden.

3.1. Datenbank und Benutzer konfigurieren

Sobald unser Cluster in Betrieb ist, müssen wir über die mit CockroachDB bereitgestellte SQL-Konsole unsere Datenbank und einen Benutzer erstellen.

Lassen Sie uns zunächst die SQL-Konsole starten:

cockroach sql --insecure;

Jetzt erstellen wir unseretestdb-Datenbank, erstellen einen Benutzer und fügen dem Benutzer Zuschüsse hinzu, um CRUD-Operationen ausführen zu können:

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

Wenn wir überprüfen möchten, ob die Datenbank korrekt erstellt wurde, können wir alle im aktuellen Knoten erstellten Datenbanken auflisten:

SHOW DATABASES;

Wenn wir die automatische Replikationsfunktion von CockroachDB überprüfen möchten, können wir auf einem der beiden anderen Knoten überprüfen, ob die Datenbank korrekt erstellt wurde. Dazu müssen wir dasport-Flag ausdrücken, wenn wir die SQL-Konsole verwenden:

cockroach sql --insecure --port=26258;

4. Überwachung von CockroachDB

Nachdem wir unseren lokalen Cluster gestartet und die Datenbank erstellt haben,we can monitor them using the CockroachDB Admin UI:

image

Auf diese Admin-Benutzeroberfläche, die im Lieferumfang von CockroachDB enthalten ist, kann mithttp://localhost:8080 zugegriffen werden, sobald der Cluster betriebsbereit ist. Insbesondereit provides details about cluster and database configuration, and helps us optimize cluster performance by monitoring metrics like:

  • Cluster Health - wesentliche Kennzahlen zum Zustand des Clusters

  • Runtime Metrics - Metriken zu Knotenanzahl, CPU-Zeit und Speichernutzung

  • SQL Performance - Metriken zu SQL-Verbindungen, Abfragen und Transaktionen

  • Replication Details - Metriken darüber, wie Daten im gesamten Cluster repliziert werden

  • Node Details - Details zu lebenden, toten und stillgelegten Knoten

  • Database Details - Details zu den System- und Benutzerdatenbanken im Cluster

5. Project Setup

Angesichts unseres laufenden lokalen Clusters von CockroachDB müssen wir unserenpom.xml: einadditional dependency hinzufügen, um eine Verbindung herstellen zu können


    org.postgresql
    postgresql
    42.1.4

Oder für ein Gradle-Projekt:

compile 'org.postgresql:postgresql:42.1.4'

6. Verwenden von CockroachDB

Nachdem klar ist, womit wir arbeiten und alles richtig eingerichtet ist, können wir es verwenden.

Dank der PostgreSQL-Kompatibilität wurdenit’s either possible to connect directly with JDBC or using an ORM, such as Hibernate (Zum Zeitpunkt des Schreibens (Januar 2018) wurden beide Treiber ausreichend getestet, um laut Entwicklern die Unterstützung vonbeta-levelzu beanspruchen). In unserem Fall verwenden wir JDBC, um mit der Datenbank zu interagieren.

Der Einfachheit halber werden wir uns mit den grundlegenden CRUD-Operationen befassen, da diese am besten zu Beginn sind.

Beginnen wir mit der Verbindung zur Datenbank.

6.1. Verbindung zu CockroachDB herstellen

Um eine Verbindung mit der Datenbank herzustellen, können wir die MethodegetConnection()der KlasseDriverManagerverwenden. Diese Methode erfordert den Parameter der Verbindungs-URLString, einen Benutzernamen und ein Kennwort:

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

6.2. Eine Tabelle erstellen

Mit einer funktionierenden Verbindung können wir die Tabellearticleserstellen, die wir für alle CRUD-Operationen verwenden werden:

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);

Wenn wir überprüfen möchten, ob die Tabelle ordnungsgemäß erstellt wurde, können wir den BefehlSHOW TABLES verwenden:

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)));

Mal sehen, wie es möglich ist, die gerade erstellte Tabelle zu ändern.

6.3. Eine Tabelle ändern

Wenn wir einige Spalten während der Tabellenerstellung verpasst haben oder sie später benötigen, können wir sie problemlos hinzufügen:

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);

Sobald wir die Tabelle geändert haben, können wir mit dem BefehlSHOW COLUMNS FROM überprüfen, ob die neue Spalte hinzugefügt wurde:

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. Eine Tabelle löschen

Wenn wir mit Tabellen arbeiten, müssen wir sie manchmal löschen, und dies kann leicht mit wenigen Codezeilen erreicht werden:

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

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

6.5. Daten einfügen

Sobald Sie die Operationen gelöscht haben, die für eine Tabelle ausgeführt werden können, können Sie mit der Arbeit mit Daten beginnen. Wir können mit der Definition der KlasseArticlebeginnen:

public class Article {

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

    // standard constructor/getters/setters
}

Jetzt können wir sehen, wie wirArticle zu unsererarticles-Tabelle hinzufügen:

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. Daten lesen

Sobald die Daten in einer Tabelle gespeichert sind, möchten wir diese Daten lesen und dies kann leicht erreicht werden:

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

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

Wenn wir jedoch nicht alle Daten in der Tabellearticleslesen möchten, sondern nur eineArticle, können wir einfach ändern, wie wir unserePreparedStatementerstellen:

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. Daten löschen

Wenn wir Daten aus unserer Tabelle entfernen möchten, können wir mit dem StandardbefehlDELETE FROM einen begrenzten Satz von Datensätzen löschen:

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();

Oder wir können den gesamten Datensatz in der Tabelle mit der FunktionTRUNCATE löschen:

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

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

6.8. Transaktionen abwickeln

Sobald eine Verbindung zur Datenbank besteht, wird jede einzelne SQL-Anweisung standardmäßig als Transaktion behandelt und unmittelbar nach Abschluss der Ausführung automatisch festgeschrieben.

Wenn wir jedoch zulassen möchten, dass zwei oder mehr SQL-Anweisungen zu einer einzigen Transaktion zusammengefasst werden, müssen wir die Transaktion programmgesteuert steuern.

Zuerst müssen wir den Auto-Commit-Modus deaktivieren, indem wir die EigenschaftautoCommit vonConnection auffalse setzen und dann die Methodencommit() undrollback() zur Steuerung verwenden die Transaktion.

Lassen Sie uns sehen, wie wir bei mehreren Einfügungen Datenkonsistenz erreichen können:

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);
}

In diesem Fall wurde beim zweiten Einfügen eine Ausnahme für die Verletzung der Primärschlüsseleinschränkung ausgelöst, und daher wurden keine Artikel in die Tabellearticleseingefügt.

7. Fazit

In diesem Artikel haben wir erklärt, was CockroachDB ist, wie ein einfacher lokaler Cluster eingerichtet wird und wie wir von Java aus damit interagieren können.

Der vollständige Quellcode für diesen Artikel ist wie immerover on Github.