1. 引言

本教程是Java中使用CockroachDB的入门指南。我们将介绍其核心特性、如何配置本地集群及监控方法,并重点讲解如何通过Java连接和操作数据库

首先来明确CockroachDB是什么。

2. CockroachDB简介

CockroachDB是一个构建在事务性一致性键值存储之上的分布式SQL数据库。它使用Go语言编写且完全开源,核心设计目标是支持ACID事务、水平扩展和高可用性。基于这些目标,它能从容应对从单盘故障到整个数据中心崩溃的场景,且延迟影响最小、无需人工干预。

因此,CockroachDB非常适合需要高可靠、高可用且数据一致性强的应用场景。但要注意,当极低延迟读写成为关键需求时,它并非首选方案。

2.1. 核心特性

继续探索CockroachDB的关键特性:

  • SQL API与PostgreSQL兼容 - 支持结构化、操作和查询数据
  • ACID事务支持 - 支持分布式事务并提供强一致性保证
  • 云原生就绪 - 可在云端或本地部署,支持跨云服务商无缝迁移
  • 水平扩展能力 - 通过简单添加新节点即可扩容,运维开销极低
  • 数据自动复制 - 通过复制保障可用性,确保副本间一致性
  • 自动故障修复 - 短期故障时只要多数副本可用即可持续服务;长期故障时自动使用健康副本重建数据

3. 配置CockroachDB

安装CockroachDB后,启动本地集群的第一个节点:

cockroach start --insecure --host=localhost;

为演示方便,我们使用--insecure参数跳过加密通信和证书配置。此时单节点集群已运行,但要充分利用CockroachDB的自动复制、重平衡和容错能力,建议再添加两个节点

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;

新增节点时,我们使用--join参数指定首个节点的地址(本例为localhost:26257)。注意本地集群中每个节点必须配置唯一的storeporthttp-port

在真实分布式集群中,各节点部署在不同机器,可省略端口配置(使用默认值),且--join参数应使用首个节点的实际IP。

3.1. 配置数据库和用户

集群启动后,通过CockroachDB内置的SQL控制台创建数据库和用户。首先启动控制台:

cockroach sql --insecure;

创建testdb数据库、用户并授权:

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

验证数据库创建情况:

SHOW DATABASES;

要验证自动复制功能,可在其他节点检查数据库是否同步(需指定端口):

cockroach sql --insecure --port=26258;

4. 监控CockroachDB

集群和数据库创建后,可通过CockroachDB Admin UI进行监控

CockroachDB监控界面

Admin UI随CockroachDB一同提供,集群启动后可通过http://localhost:8080访问。它提供集群和数据库配置详情,并通过监控以下指标帮助优化性能:

  • 集群健康状态 - 集群健康关键指标
  • 运行时指标 - 节点数、CPU时间、内存使用情况
  • SQL性能 - SQL连接、查询和事务指标
  • 复制详情 - 集群数据复制情况
  • 节点详情 - 活跃、失效和已退役节点信息
  • 数据库详情 - 系统和用户数据库信息

5. 项目配置

在运行中的CockroachDB集群上,需添加PostgreSQL JDBC驱动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月,官方称驱动支持达到beta级别)。本文采用JDBC方式。

从基础CRUD操作开始,先建立数据库连接。

6.1. 连接CockroachDB

使用DriverManager.getConnection()方法建立连接,需提供连接URL、用户名和密码:

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

验证表创建情况:

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

验证新列是否添加成功:

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;

    // 标准构造器/getter/setter
}

插入数据:

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

查询单条记录:

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. 删除数据

删除特定记录:

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

清空表(⚠️ 慎用):

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

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

6.8. 事务处理

默认情况下,每个SQL语句作为独立事务自动提交。若需将多个语句组合为事务,需手动控制:

  1. 关闭自动提交:con.setAutoCommit(false)
  2. 使用commit()rollback()控制事务

批量插入示例:

try {
    con.setAutoCommit(false);

    UUID articleId = UUID.randomUUID();

    Article article = new Article(
      articleId, "Java中使用CockroachDB完全指南", "baeldung"
    );
    articleRepository.insertArticle(article);

    article = new Article(
      articleId, "Java MongoDB指南", "baeldung"
    );
    articleRepository.insertArticle(article); // 主键冲突抛异常

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

✅ 第二次插入因主键冲突失败,整个事务回滚,无数据插入。

7. 总结

本文介绍了CockroachDB的核心概念、本地集群搭建方法,以及如何通过Java进行数据库操作。完整代码示例可在GitHub获取。


原始标题:Guide to CockroachDB in Java