1. 序章

このチュートリアルは、JavaでCockroachDBを使用するための入門ガイドです。

主な機能、ローカルクラスターの構成方法と監視方法、と、Javaを使用してサーバーに接続して対話する方法に関する実用的なガイドについて説明します。

それが何であるかを最初に定義することから始めましょう。

2. CockroachDB

CockroachDBは、トランザクション型で一貫性のあるKey-Valueストアの上に構築された分散SQLデータベースです。

Goと完全にオープンソースで記述されたの主な設計目標は、ACIDトランザクション、水平方向のスケーラビリティ、および存続可能性のサポートです。これらの設計目標により、単一のディスク障害からデータセンター全体まですべてを許容することを目的としています。レイテンシーの中断を最小限に抑え、手動による介入なしでクラッシュします。

その結果、 CockroachDBは、規模に関係なく、信頼性が高く、利用可能で、正しいデータを必要とするアプリケーションに最適なソリューションと見なすことができます。ただし、非常に低遅延の読み取りと書き込みが重要な場合は、これが最初の選択肢ではありません。

2.1. 主な機能

CockroachDBの重要な側面のいくつかを探求し続けましょう:

  • SQLAPIとPostgreSQLの互換性–データの構造化、操作、クエリ用
  • ACIDトランザクション–分散トランザクションをサポートし、強力な一貫性を提供します
  • クラウド対応–クラウドまたはオンプレミスソリューションで実行するように設計されており、サービスを中断することなく、異なるクラウドプロバイダー間で簡単に移行できます
  • 水平方向に拡張–容量の追加は、最小限のオペレーターオーバーヘッドで、実行中のクラスターに新しいノードを向けるのと同じくらい簡単です。
  • Replication –可用性のためにデータを複製し、レプリカ間の一貫性を保証します
  • 自動修復–レプリカの大部分が短期的な障害に利用できる限りシームレスに続行し、長期的な障害の場合は、影響を受けていないレプリカをソースとして使用して、欠落しているノードからレプリカを自動的に再調整します

3. CockroachDBの構成

CockroachDB インストールした後、ローカルクラスターの最初のノードを起動できます。

cockroach start --insecure --host=localhost;

デモの目的で、 insecure 属性を使用して、証明書の場所を指定することなく、通信を暗号化しないようにします。

この時点で、ローカルクラスターが稼働しています。 単一のノードだけで、すでに接続して操作できますが、 CockroachDBの自動レプリケーション、リバランス、およびフォールトトレランスをより有効に活用するために、さらに2つのノードを追加します。

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;

追加の2つのノードについては、 join フラグを使用して、新しいノードをクラスターに接続し、最初のノード(この場合はlocalhost:26257)のアドレスとポートを指定しました。 ローカルクラスター上の各ノードには、一意のストア、ポート、およびhttpポートの値が必要です。

CockroachDBの分散クラスターを構成する場合、各ノードは異なるマシン上にあるため、ポートストア、およびhttp-portの指定を回避できます。デフォルト値で十分なので。 さらに、追加のノードをクラスターに参加させるときは、最初のノードの実際のIPを使用する必要があります。

3.1. データベースとユーザーの構成

クラスターを起動して実行したら、CockroachDBで提供されるSQLコンソールを使用して、データベースとユーザーを作成する必要があります。

まず、SQLコンソールを起動しましょう。

cockroach sql --insecure;

それでは、 testdb データベースを作成し、ユーザーを作成して、CRUD操作を実行できるようにするためにユーザーに付与を追加しましょう。

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

データベースが正しく作成されたことを確認する場合は、現在のノードで作成されたすべてのデータベースを一覧表示できます。

SHOW DATABASES;

最後に、CockroachDBの自動レプリケーション機能を検証する場合は、データベースが正しく作成されているかどうかを他の2つのノードのいずれかで確認できます。 そのためには、SQLコンソールを使用しているときにportフラグを表現する必要があります。

cockroach sql --insecure --port=26258;

4. CockroachDBの監視

ローカルクラスターを開始してデータベースを作成したので、 CockroachDB AdminUIを使用してそれらを監視できます。

CockroachDBにバンドルされているこの管理UIは、クラスターが稼働するとすぐに http:// localhost:8080からアクセスできます。 特に、はクラスターとデータベースの構成に関する詳細を提供し、のようなメトリックを監視することでクラスターのパフォーマンスを最適化するのに役立ちます。

  • クラスターの正常性–クラスターの正常性に関する重要なメトリック
  • ランタイムメトリクス–ノード数、CPU時間、およびメモリ使用量に関するメトリクス
  • SQLパフォーマンス– SQL接続、クエリ、およびトランザクションに関するメトリック
  • レプリケーションの詳細–データがクラスター全体でどのようにレプリケートされるかに関するメトリック
  • ノードの詳細–稼働中、停止中、および廃止されたノードの詳細
  • データベースの詳細–クラスター内のシステムおよびユーザーデータベースに関する詳細

5. プロジェクト設定

CockroachDBの実行中のローカルクラスターを前提として、それに接続できるようにするには、追加の依存関係 pom.xml:に追加する必要があります。

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.1.4</version>
</dependency>

または、Gradleプロジェクトの場合:

compile 'org.postgresql:postgresql:42.1.4'

6. CockroachDBの使用

作業内容が明確になり、すべてが適切に設定されたので、使用を開始しましょう。

PostgreSQLとの互換性のおかげで、 JDBCに直接接続するか、Hibernate などのORMを使用することができます(執筆時点(2018年1月)では、両方のドライバーがを要求するのに十分なテストが行われています。開発者によると、ベータレベルのサポート)。 この例では、JDBCを使用してデータベースと対話します。

簡単にするために、最初は基本的なCRUD操作を使用するのが最適です。

データベースに接続することから始めましょう。

6.1. CockroachDBへの接続

データベースとの接続を開くには、 DriverManagerクラスのgetConnection()メソッドを使用できます。 このメソッドには、接続URL String パラメーター、ユーザー名、およびパスワードが必要です。

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

6.2. テーブルの作成

接続が機能していれば、すべてのCRUD操作に使用するarticlesテーブルの作成を開始できます。

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

テーブルが正しく作成されたことを確認する場合は、 SHOWTABLESコマンドを使用できます。

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

作成したばかりのテーブルを変更する方法を見てみましょう。

6.3. テーブルの変更

テーブルの作成中にいくつかの列を見逃した場合、または後でそれらが必要になったために、それらを簡単に追加できます。

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

テーブルを変更したら、 SHOW COLUMNSFROMコマンドを使用して新しい列が追加されたかどうかを確認できます。

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

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

6.4. テーブルの削除

テーブルを操作するとき、テーブルを削除する必要がある場合があります。これは、数行のコードで簡単に実現できます。

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

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

6.5. データの挿入

テーブルで実行できる操作をクリアしたら、データの操作を開始できます。 Articleクラスの定義を開始できます。

public class Article {

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

    // standard constructor/getters/setters
}

これで、Articlearticlesテーブルに追加する方法を確認できます。

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. データの読み取り

データがテーブルに格納されたら、それらのデータを読み取りたいので、これは簡単に実現できます。

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

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

ただし、 articles テーブル内のすべてのデータを読み取るのではなく、 Article を1つだけ読み取る場合は、PreparedStatementの作成方法を変更するだけです。

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. データの削除

最後になりましたが、テーブルからデータを削除する場合は、標準の DELETE 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();

または、 TRUNCATE 関数を使用して、テーブル内のすべてのレコードを削除できます。

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

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

6.8. トランザクションの処理

データベースに接続されると、デフォルトでは、個々のSQLステートメントはトランザクションとして扱われ、実行が完了した直後に自動的にコミットされます。

ただし、2つ以上のSQLステートメントを1つのトランザクションにグループ化できるようにする場合は、プログラムでトランザクションを制御する必要があります。

まず、ConnectionautoCommitプロパティをfalseに設定して自動コミットモードを無効にしてから、 commit()を使用する必要があります。 ]およびrollback()メソッドを使用してトランザクションを制御します。

複数の挿入を行うときにデータの一貫性を実現する方法を見てみましょう。

try {
    con.setAutoCommit(false);

    UUID articleId = UUID.randomUUID();

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

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

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

この場合、2回目の挿入で、主キー制約の違反に対して例外がスローされたため、articlesテーブルに記事は挿入されませんでした。

7. 結論

この記事では、CockroachDBとは何か、単純なローカルクラスターをセットアップする方法、およびJavaからCockroachDBと対話する方法について説明しました。

この記事の完全なソースコードは、いつものように、Githubにあります。