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
)。注意本地集群中每个节点必须配置唯一的store
、port
和http-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进行监控:
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语句作为独立事务自动提交。若需将多个语句组合为事务,需手动控制:
- 关闭自动提交:
con.setAutoCommit(false)
- 使用
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获取。