1. 概述

DataStax 发行版的 Apache Cassandra 是一个可用于生产环境的分布式数据库,兼容开源版本的 Cassandra。它在开源功能基础上增加了一些高级特性,例如增强的监控能力、更高效的批量处理和流式数据支持。

DataStax 还为其 Cassandra 发行版提供了官方 Java 客户端驱动。这个驱动高度可配置,既能充分利用 DataStax 专有功能,又能完全兼容开源版 Cassandra —— ✅ 一套代码,双端通吃。

本文将带你使用 DataStax Java Driver for Apache Cassandra 连接 Cassandra 数据库,并完成基础的数据操作。内容不讲废话,直奔实战。


2. Maven 依赖

要使用 DataStax Java Driver,首先得把依赖加进项目。

使用 Maven 的同学,在 pom.xml 中加入以下两个核心依赖:

<dependency>
    <groupId>com.datastax.oss</groupId>
    <artifactId>java-driver-core</artifactId>
    <version>4.10.0</version>
</dependency>

<dependency>
    <groupId>com.datastax.oss</groupId>
    <artifactId>java-driver-query-builder</artifactId>
    <version>4.10.0</version>
</dependency>

⚠️ 注意:示例中版本为 4.1.0,建议升级到较新稳定版(如 4.10.0+),避免踩到已知 bug。

  • java-driver-core:驱动核心,负责连接、执行、结果处理
  • java-driver-query-builder:提供类型安全的 CQL 构建器,告别拼接字符串

3. 使用 DataStax 驱动

依赖搞定后,接下来就是实操环节。

3.1. 连接数据库

连接 Cassandra 的核心是创建一个 CqlSession 实例。

最简单的连接方式:

CqlSession session = CqlSession.builder().build();

✅ 默认行为:

  • 联系点(contact point):127.0.0.1:9042
  • 本地数据中心:自动探测(不推荐生产使用)

实际开发中,我们通常需要自定义连接参数。封装一个连接管理类更便于复用:

public class CassandraConnector {

    private CqlSession session;

    public void connect(String node, Integer port, String dataCenter) {
        CqlSessionBuilder builder = CqlSession.builder();
        builder.addContactPoint(new InetSocketAddress(node, port));
        builder.withLocalDatacenter(dataCenter); // 必须设置,否则多 DC 环境会报错

        session = builder.build();
    }

    public CqlSession getSession() {
        return this.session;
    }

    public void close() {
        if (session != null) {
            session.close();
        }
    }
}

📌 踩坑提醒:

  • withLocalDatacenter() 是必须的,否则会抛 No local DC defined 异常
  • 生产环境建议配置多个 contact points 实现高可用

3.2. 创建 Keyspace

连接建立后,先创建命名空间(keyspace),相当于关系型数据库中的“数据库”。

使用 SchemaBuilder 构建 CQL 语句,避免手写字符串出错:

public class KeyspaceRepository {

    private final CqlSession session;

    public KeyspaceRepository(CqlSession session) {
        this.session = session;
    }

    public void createKeyspace(String keyspaceName, int numberOfReplicas) {
        CreateKeyspace createKeyspace = SchemaBuilder.createKeyspace(keyspaceName)
          .ifNotExists()
          .withSimpleStrategy(numberOfReplicas);

        session.execute(createKeyspace.build());
    }

    public void useKeyspace(String keyspace) {
        session.execute("USE " + CqlIdentifier.fromCql(keyspace));
    }
}

📌 说明:

  • 使用 SimpleStrategy 策略,适合单数据中心测试环境
  • 多数据中心生产环境应使用 NetworkTopologyStrategy
  • ifNotExists() 防止重复创建

3.3. 创建表

定义一个 Video 实体类作为示例:

public class Video {
    private UUID id;
    private String title;
    private Instant creationDate;

    // 构造方法、getter/setter 省略
}

接着创建对应的表结构:

public class VideoRepository {

    private static final String TABLE_NAME = "videos";
    private final CqlSession session;

    public VideoRepository(CqlSession session) {
        this.session = session;
    }

    public void createTable() {
        createTable(null);
    }

    public void createTable(String keyspace) {
        CreateTable createTable = SchemaBuilder.createTable(TABLE_NAME)
          .withPartitionKey("video_id", DataTypes.UUID)
          .withColumn("title", DataTypes.TEXT)
          .withColumn("creation_date", DataTypes.TIMESTAMP);

        executeStatement(createTable.build(), keyspace);
    }

    private ResultSet executeStatement(SimpleStatement statement, String keyspace) {
        if (keyspace != null) {
            statement = statement.setKeyspace(CqlIdentifier.fromCql(keyspace));
        }
        return session.execute(statement);
    }
}

✅ 方法重载设计的好处:

  • createTable():在当前 session 使用的 keyspace 中建表
  • createTable(keyspace):指定 keyspace 建表,不依赖当前 session 状态

这种设计更灵活,适合多租户或模块化系统。


3.4. 插入数据

插入数据推荐使用 预编译语句(PreparedStatement) + 绑定参数(BoundStatement),性能更高且防注入。

public UUID insertVideo(Video video, String keyspace) {
    UUID videoId = UUID.randomUUID();
    video.setId(videoId);

    RegularInsert insertInto = QueryBuilder.insertInto(TABLE_NAME)
      .value("video_id", QueryBuilder.bindMarker())
      .value("title", QueryBuilder.bindMarker())
      .value("creation_date", QueryBuilder.bindMarker());

    SimpleStatement insertStatement = insertInto.build();
    if (keyspace != null) {
        insertStatement = insertStatement.setKeyspace(keyspace);
    }

    PreparedStatement preparedStatement = session.prepare(insertStatement);

    BoundStatement statement = preparedStatement.bind()
      .setUuid(0, video.getId())
      .setString(1, video.getTitle())
      .setInstant(2, video.getCreationDate());

    session.execute(statement);
    return videoId;
}

📌 关键点:

  • bindMarker() 生成占位符 ?
  • prepare() 提升重复执行效率
  • 按索引设置值(从 0 开始),也可按名称绑定

3.5. 查询数据

查询同样使用 QueryBuilder 构建语句,简洁又安全:

public List<Video> selectAll(String keyspace) {
    Select select = QueryBuilder.selectFrom(TABLE_NAME).all();
    ResultSet resultSet = executeStatement(select.build(), keyspace);

    List<Video> result = new ArrayList<>();
    resultSet.forEach(row -> result.add(
        new Video(
            row.getUuid("video_id"),
            row.getString("title"),
            row.getInstant("creation_date")
        )
    ));
    return result;
}

⚠️ 注意:

  • ResultSet 是迭代器模式,不要多次遍历
  • 推荐尽早转换为 POJO 列表,避免 session 关闭后无法读取

3.6. 完整示例

把上面所有组件串起来跑一遍:

public class Application {

    private static final Logger LOG = LoggerFactory.getLogger(Application.class);

    public void run() {
        CassandraConnector connector = new CassandraConnector();
        connector.connect("127.0.0.1", 9042, "datacenter1");
        CqlSession session = connector.getSession();

        KeyspaceRepository keyspaceRepo = new KeyspaceRepository(session);
        keyspaceRepo.createKeyspace("testKeyspace", 1);
        keyspaceRepo.useKeyspace("testKeyspace");

        VideoRepository videoRepo = new VideoRepository(session);
        videoRepo.createTable();

        videoRepo.insertVideo(new Video("视频1", Instant.now()), "testKeyspace");
        videoRepo.insertVideo(new Video("视频2", Instant.now().minus(1, ChronoUnit.DAYS)), "testKeyspace");

        List<Video> videos = videoRepo.selectAll("testKeyspace");
        videos.forEach(video -> LOG.info(video.toString()));

        connector.close();
    }
}

执行结果(日志输出):

INFO com.example.Application - [id:733249eb-914c-4153-8698-4f58992c4ad4, title:视频1, creationDate: 2019-07-10T19:43:35.112Z]
INFO com.example.Application - [id:a6568236-77d7-42f2-a35a-b4c79afabccf, title:视频2, creationDate: 2019-07-09T19:43:35.181Z]

数据成功落库,收工。


4. 总结

本文带你快速上手 DataStax Java Driver 的核心用法:

  • ✅ 添加 Maven 依赖
  • ✅ 建立连接(CqlSession)
  • ✅ 操作 Keyspace 与表
  • ✅ 使用 PreparedStatement 插入数据
  • ✅ 查询并映射结果

整个过程简单粗暴,没有多余的理论铺垫。适合有数据库经验的开发者直接套用。

📌 源码已托管至 GitHub:https://github.com/baeldung/java-cassandra

后续可深入学习:

  • 异步执行(Async API)
  • 自定义类型映射(Codec)
  • 重试策略与负载均衡
  • 批量操作与事务模拟

Cassandra 的优势在于高写入、高可用,搭配 DataStax Driver 能充分发挥其潜力。生产项目中建议结合连接池、监控和熔断机制使用。


原始标题:Intro to DataStax Java Driver for Apache Cassandra | Baeldung