JavaによるCockroachDBガイド

JavaでのCockroachDBのガイド

1. 前書き

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

主な機能、ローカルクラスターの構成方法と監視方法、along with a practical guide on how we can use Java to connect and interact with the server.について説明します。

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

2. CockroachDB

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

Goで記述され、完全にオープンソースのits primary design goals are the support for ACID transactions, horizontal scalability, and survivability.これらの設計目標により、単一のディスク障害からデータセンター全体のクラッシュまで、遅延の中断を最小限に抑え、手動による介入なしですべてを許容することを目的としています。

その結果、CockroachDB can be considered a well-suited solution for applications that require reliable, available, and correct data regardless of scale.ただし、非常に低遅延の読み取りと書き込みが重要な場合は、これが最初の選択肢ではありません。

2.1. 主な機能

CockroachDBの重要な側面のいくつかを引き続き調べてみましょう。

  • SQL API and PostgreSQL compatibility –データの構造化、操作、およびクエリ用

  • ACID transactions –分散トランザクションをサポートし、強力な一貫性を提供します

  • Cloud-ready –クラウドまたはオンプレミスソリューションで実行するように設計されており、サービスを中断することなく、異なるクラウドプロバイダー間で簡単に移行できます。

  • Scales horizontally –容量の追加は、最小限のオペレーターオーバーヘッドで、実行中のクラスターに新しいノードを指定するのと同じくらい簡単です。

  • Replication –可用性のためにデータを複製し、レプリカ間の一貫性を保証します

  • Automated repair –レプリカの大部分が短期的な障害に利用できる限りシームレスに続行し、長期的な障害の場合は、影響を受けていないレプリカをソースとして使用して、欠落しているノードからレプリカを自動的に再調整します

3. CockroachDBの構成

installed CockroachDBを実行したら、ローカルクラスターの最初のノードを開始できます。

cockroach start --insecure --host=localhost;

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

この時点で、ローカルクラスターは稼働しています。 単一のノードが1つしかないので、すでに接続して操作できますが、to 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;

追加の2つのノードについては、joinフラグを使用して新しいノードをクラスターに接続し、最初のノード(この場合はlocalhost:26257)のアドレスとポートを指定しました。 Each node on the local cluster requires unique store, port, and http-port values.

CockroachDBの分散クラスターを構成する場合、各ノードは異なるマシン上にあるため、デフォルト値で十分なので、portstore、および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の監視

これで、ローカルクラスターを開始し、データベースwe can monitor them using the CockroachDB Admin UIを作成しました。

image

CockroachDBにバンドルされているこの管理UIは、クラスターが稼働するとすぐにhttp://localhost:8080でアクセスできます。 特に、it provides details about cluster and database configuration, and helps us optimize cluster performance by monitoring metrics like

  • Cluster Health –クラスターの状態に関する重要なメトリック

  • Runtime Metrics –ノード数、CPU時間、およびメモリ使用量に関するメトリック

  • SQL Performance – SQL接続、クエリ、およびトランザクションに関するメトリック

  • Replication Details –データがクラスター全体に複製される方法に関するメトリック

  • Node Details –ライブ、デッド、および廃止されたノードの詳細

  • Database Details –クラスター内のシステムおよびユーザーデータベースに関する詳細

5. Project Setup

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


    org.postgresql
    postgresql
    42.1.4

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

compile 'org.postgresql:postgresql:42.1.4'

6. CockroachDBの使用

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

PostgreSQLの互換性のおかげで、it’s either possible to connect directly with JDBC or using an ORM, such as Hibernate(開発者によると、執筆時点(2018年1月)では、両方のドライバーがbeta-levelのサポートを主張するのに十分なテストが行​​われています)。 この例では、JDBCを使用してデータベースを操作します。

簡単にするために、最初に最適な基本的なCRUD操作について説明します。

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

6.1. CockroachDBへの接続

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

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

テーブルが正しく作成されたことを確認する場合は、SHOW 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)));

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

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 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. テーブルを削除する

テーブルを操作するとき、時々テーブルを削除する必要があり、これは数行のコードで簡単に達成できます:

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
}

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

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テーブル内のすべてのデータを読み取るのではなく、1つのArticleを読み取る場合は、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", "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);
}

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

7. 結論

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

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