You need to enable JavaScript to run this app.
ByteHouse云数仓版

ByteHouse云数仓版

复制全文
JDBC
ByteHouse JDBC Driver
复制全文
ByteHouse JDBC Driver

ByteHouse JDBC Driver 是用于 Java 应用通过 JDBC 接口连接 ByteHouse 云数仓的驱动程序,支持数据查询、写入等操作,可帮助 Java 开发者快速集成 ByteHouse,实现高效的数据访问。本文介绍如何通过 JDBC 方式连接并访问 ByteHouse 云数仓。

环境要求

支持 Java 1.8.0_261 或更高版本 (需要 TLS v1.3 支持)。

推荐版本

推荐使用 ByteHouse JDBC Driver 最新版本。您可前往 ByteHouse Java Driver index 页面,获取 ByteHouse JDBC Driver 最新版本的 jar 文件。

驱动兼容性

部分 SQL/ Function 受驱动版本影响,详情参阅下表。

SQL/Function

驱动版本

replace into

≥1.1.67

安装驱动

本地安装

请单击前往 ByteHouse Java Driver index 页面,获取 ByteHouse JDBC Driver 最新版本的 jar 文件。
获取 jar 文件后,您只需将编译后的 jar 文件添加到您的项目中,或者使用您选择的依赖项管理工具将此项目添加为依赖项。然后,您可以导入并使用 Java 程序中的类。

添加为 Gradle 依赖

通过 Gradle 方式使用 ByteHouse JDBC 驱动的示例如下:

repositories {
    // This is public bytedance repository for downloading artifacts 
    maven {
        url "https://artifact.bytedance.com/repository/releases"
    }
}

dependencies {
    implementation "com.bytedance.bytehouse:driver-java:1.1.74:all"
}

说明

以上示例中,java:1.1.74为一个示例的版本号,实际使用时,您需替换为最新的版本号。前往 ByteHouse Java Driver index 页面获取最新版本的驱动文件。

添加为 Maven 依赖

通过 Maven 方式使用 ByteHouse JDBC 驱动的示例如下:

// This is public bytedance repository for downloading artifacts 
<repository>
    <id>bytedance</id>
    <name>ByteDance Public Repository</name>
    <url>https://artifact.bytedance.com/repository/releases</url>
</repository>

<dependency>
    <groupId>com.bytedance.bytehouse</groupId>
    <artifactId>driver-java</artifactId>
    <version>1.1.74</version>
    <classifier>all</classifier>
</dependency> 

说明

以上示例中,java:1.1.74为一个示例的版本号,实际使用时,您需替换为最新的版本号。前往 ByteHouse Java Driver index 页面获取最新版本的驱动文件。

获取 ByteHouse 连接信息

ByteHouse 支持通过 IAM 用户或数据库用户连接 ByteHouse JDBC Driver。IAM 用户与数据库用户二者差异说明如下,您可按需选择。

  • IAM 用户为火山引擎访问控制(IAM)中创建的用户,其权限由 IAM 权限策略及您授予的 ByteHouse 资源和数据权限决定。IAM 用户可访问 ByteHouse 控制台,也支持通过 CLI、连接驱动、生态工具、API 等方式访问 ByteHouse。
  • 数据库用户为 ByteHouse 中创建的数据库级别用户,可为其授予环境、资源和数据权限。数据库用户不可访问 ByteHouse 控制台,但支持通过 CLI、连接驱动、生态工具、API 等方式访问 ByteHouse。

更多 IAM 用户和数据库用户的介绍请参见以下文档:

IAM 用户

请参考步骤三:获取 ByteHouse 连接串信息,了解如何通过 IAM 用户方式连接到 ByteHouse。
通用参数说明如下:

参数

配置说明

Host

配置为 ByteHouse 的公网/私网域名,您可以在 ByteHouse 控制台的租户管理 > 基本信息 > 网络信息中查看并复制域名信息,详情请参见步骤二:配置网络信息

Port

固定为 19000。

User

固定为 bytehouse。

Password

为 ByteHouse 的 API Key,您可以在 ByteHouse 控制台的租户管理 > 连接信息中获取 API Key,详情请参见获取 API Key

Database

配置为连接 ByteHouse 数据库名称。您可登录 ByteHouse控制台,在数据库页面查看并复制数据库。

virtual_warehouse

可选配置,配置为计算组名。如果您需要指定计算组进行查询和写入,可配置该参数。
您可登录 ByteHouse 控制台,单击顶部计算组,查看并复制计算组 ID。示例:vw-{environment_id}{account_id}-{virtual_warehouse_name}
如果不配置,则默认使用您在 ByteHouse 设置的默认计算组。

数据库用户

请参考步骤三:获取 ByteHouse 连接串信息,了解如何通过数据库用户的方式连接到 ByteHouse。
通用参数说明如下:

参数

配置说明

Host

配置为 ByteHouse 的公网/私网域名,您可以在 ByteHouse 控制台的租户管理 > 基本信息 > 网络信息中查看并复制域名信息,详情请参见步骤二:配置网络信息

Port

固定为 19000。

User

username 配置为 {accountID_or_accountName}::{username}[::{envID}],详情请参见获取数据库用户及密码

  • {accountID_or_accountName} :指火山引擎用户账号 ID 或名称,可登录 ByteHouse 控制台,单击右上角个人中心查看并复制账号 ID 或名称。

  • {username} :指登录 ByteHouse 数据库账号的用户名。可在ByteHouse 控制台 > 权限管理 > 用户 > 查看数据库用户名

  • {envID}:可选配置,数据库所在的环境名称。如果使用 default 环境,可不配置;如需使用其他环境,需指定环境名称,配置时无需添加[]。您可登录 ByteHouse 控制台,在租户管理 > 基本信息 > 当前环境中获取。

    使用示例如下:

    • 配置环境 ID:21xxxxxxxx::demouser::demoenv
    • 不配置环境 ID:21xxxxxxxx::demouser

Password

数据库账号的密码由管理员创建数据库账号时自定义配置,您可联系管理员获取密码。如果密码丢失或遗忘,可通联系管理员重置密码,详情请参考重置密码

Database

配置为连接 ByteHouse 数据库名称。您可登录 ByteHouse控制台,在数据库页面查看并复制数据库。

virtual_warehouse

可选配置,配置为计算组名。如果您需要指定计算组进行查询和写入,可配置该参数。
您可登录 ByteHouse 控制台,单击顶部计算组,查看并复制计算组 ID。示例:vw-{environment_id}{account_id}-{virtual_warehouse_name}
如果不配置,则默认使用您在 ByteHouse 设置的默认计算组。

基本用法

您可以使用以下代码连接至 ByteHouse,并开始使用标准语句开发 ByteHouse,用于查询、写入和读取数据。

  • 超时时间配置:ping_timeout 默认为 10s、query_timeout 默认为 0s、connect_timeout 默认为 0s,send_timeout 和 receive_timeout 当前暂不生效。
  • 默认支持 keepAlive,可以复用连接和避免短链接。

连接 ByteHouse

可参考下面代码连接至 ByteHouse,使用时注意替换连接语句中的 {host}{Password}{User}{Database}{VITUAL_WAREHOUSE_ID} 等连接信息字段,获取方式请参见获取 ByteHouse 连接信息

使用 Propertities 配置连接

import com.bytedance.bytehouse.jdbc.statement.ByteHouseStatement;

import java.sql.*;
import java.util.Properties;
import java.util.UUID;

public class BHJDBC {
    public static void main(String[] args) {
        String host = "{Host}";
        int port = 19000;
        String password = "{Password}";
        String user = "{User}";
        String database = "{Database}";
        String virtual_warehouse_id = "{VIRTUAL_WAREHOUSE_ID}";

        // 通过 properties 设置一些链接的基本参数
        String url = String.format("jdbc:bytehouse://%s:%d", host, port);
        Properties properties = new Properties();
        // 可以按需设置不同的计算组
          properties.setProperty("virtual_warehouse", virtual_warehouse_id);
          properties.setProperty("secure", "true");
          properties.setProperty("user", user);
          properties.setProperty("password", password);
          properties.setProperty("database", database);

        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, properties);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

使用 URL 的 param 配置连接

import com.bytedance.bytehouse.jdbc.statement.ByteHouseStatement;

import java.sql.*;
import java.util.Properties;
import java.util.UUID;

public class BHJDBC {
    public static void main(String[] args) {
        String host = "{Host}";
        int port = 19000;
        String password = "{Password}";
        String user = "{User}";
        String database = "{Database}";
        String virtual_warehouse_id = "{VIRTUAL_WAREHOUSE_ID}";

        String url = String.format("jdbc:bytehouse://%s:%d/?secure=true&user=%s&password=%s&database=%s&virtual_warehouse=%s",
                host, port, user, password, database, virtual_warehouse_id);


        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

创建数据库、表

与 ByteHouse 建立连接后,您可以使用以下代码创建数据库、表。

public static void dropDatabase(Connection connection) {
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
            String dropDbQuery = "Drop DATABASE IF EXISTS bhjdbctest";
            stmt.execute(dropDbQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
     /*
     * 创建数据库
     */
    public static void createDatabase(Connection connection) {
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
            String createDbQuery = "CREATE DATABASE IF NOT EXISTS bhjdbctest";
            stmt.execute(createDbQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
     /*
     * 创建表
     */
    public static void createTable(Connection connection) {
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
            String createTableQuery = "CREATE TABLE IF NOT EXISTS bhjdbctest.orders\n (" +
                    "OrderID String, OrderName String, OrderPriority Int8)" +
                    " engine = CnchMergeTree() partition by OrderID order by OrderID";
            stmt.execute(createTableQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

写入数据

您可以使用以下代码写入数据。

/*
     * 插入数据
     */
    public static void insertTable(Connection connection) {
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
            String insertQuery = "INSERT INTO bhjdbctest.orders VALUES ('54895','Apple',12)";
            stmt.executeUpdate(insertQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
     /*
     * 批量插入数据
     */
    public static void insertBatch(Connection connection) {
        PreparedStatement pstmt = null;
        String insertQuery = "INSERT INTO bhjdbctest.orders (OrderID, OrderName, OrderPriority) VALUES (?,'Apple',?)";
        try {
            pstmt = connection.prepareStatement(insertQuery);
            int insertBatchSize = 10;
            for (int i = 0; i < insertBatchSize; i++) {
                pstmt.setString(1, "ID" + i);
                pstmt.setInt(2, i);
                pstmt.addBatch();
            }
            pstmt.executeBatch();

        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (pstmt != null) pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

查询

您可以使用以下代码查询数据。

/*
     * 查询数据
     */
    public static void selectTable(Connection connection) {
        Statement stmt = null;
        try {
            stmt = connection.createStatement();
            String selectTableQuery = "SELECT * FROM bhjdbctest.orders";
            ResultSet rs = stmt.executeQuery(selectTableQuery);
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnsNumber = rsmd.getColumnCount();
            while (rs.next()) {
                for (int i = 1; i <= columnsNumber; i++) {
                    if (i > 1) System.out.print(", ");
                    String columnValue = rs.getString(i);
                    System.out.print(columnValue);
                }
                System.out.println();
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

使用 Query ID

设置 query ID 有助于追踪查询执行情况,方便后续调试或管理查询任务。您可以使用 JDBC 原生方式,也可以使用 ByteHouse 专用接口,为查询语句设置 query ID。

自定义 query ID

如果您需要为某条查询语句设置 query ID,可参考以下代码,添加 stmt.setQueryId(String.format("customized_%s", UUID.randomUUID())); 代码。

public static void dropDatabaseWithQueryId(Connection connection) {
        ByteHouseStatement stmt = null;
        try {
            stmt = (ByteHouseStatement)connection.createStatement();
            stmt.setQueryId(String.format("customized_%s", UUID.randomUUID()));
            String createDbQuery = "Drop DATABASE IF EXISTS bhjdbctest";
            stmt.execute(createDbQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

使用 ByteHouse 专用接口

ByteHouse JDBC 驱动从 v1.1.83 版本起支持了为查询分配自定义 Query ID 功能。

前提条件

使用 Query ID 功能前,请确保满足以下条件:

  • ByteHouse JDBC Driver 版本为 v1.1.83 及以上。
  • 将 JDBC 接口替换为 ByteHouse 专用接口:
    • ConnectionByteHouseConnection
    • StatementByteHouseStatement
    • PreparedStatementByteHousePreparedStatement

如果使用时未明确指定 Query ID,ByteHouse JDBC 驱动将随机自动生成 Query ID,并将其与查询关联。

API 概览

API 接口

配置说明

ByteHouseConnection.setQueryId(String queryId)

仅为下一条查询设置 Query ID。

((ByteHouseConnection) connection).setQueryId("next-query-id");
connection.createStatement().executeQuery("SELECT 1");
// Query ID: "next-query-id"

ByteHouseStatement.setQueryId(String queryId)

将 Query ID 直接设置到 ByteHouseStatement 中。

ByteHouseStatement statement = (ByteHouseStatement) connection.createStatement();
statement.setQueryId("next-query-id");
statement.executeQuery("SELECT 1");
// Query ID: "next-query-id"

ByteHousePreparedStatement.setQueryId(String queryId)

JDBC 与 ByteHouse 交互的方式所限,Query ID 必须在 PreparedStatement 创建前设置。因此请勿在 PreparedStatement 上直接使用 setQueryId() 插入数据。正确示例如下:

((ByteHouseConnection) connection).setQueryId("first-query-id");
ByteHousePreparedInsertStatement ps = (ByteHousePreparedInsertStatement) connection.prepareStatement("INSERT INTO demo.tbl VALUES (?)");
ps.setObject(1, 1);
ps.execute();
// Query ID: "first-query-id"

// 为下一次查询设置新的 query ID
((ByteHouseConnection) connection).setQueryId("second-query-id");
ps.setObject(1, 2);
ps.execute();
// Query ID: "second-query-id"

ByteHouseConnection.getQueryId()

返回连接后的最后一个 Query ID。

((ByteHouseConnection) connection).setQueryId("first-query-id");
assertEquals(((ByteHouseConnection) connection).getQueryId(), "first-query-id");

ByteHousePreparedInsertStatement ps = (ByteHousePreparedInsertStatement) connection.prepareStatement("INSERT INTO demo.tbl VALUES (?)");
ps.setObject(1, 1);
ps.execute();
assertEquals(((ByteHouseConnection) connection).getQueryId(), "first-query-id");

使用会话级 Query ID 前缀

您可以使用 session_query_id_prefix 属性为所有 Query ID 设置会话级的前缀。

Properties props = new Properties();
props.setProperty("session_query_id_prefix", "my-spark-application-");

Connection connection = new ByteHouseDriver().connect(jdbcUrl, props);

示例 1:仅前缀(无显式 Query ID)

JDBC会自动为每个查询的前缀添加一个递增的计数器:

Properties props = new Properties();
props.setProperty("session_query_id_prefix", "my-spark-application-");

Connection connection = new ByteHouseDriver().connect(jdbcUrl, props);

connection.createStatement().executeQuery("DROP DATABASE IF EXISTS demo"); 
// Query ID: "my-spark-application-1"
connection.createStatement().executeQuery("CREATE DATABASE IF NOT EXISTS demo");
// Query ID: "my-spark-application-2"
connection.createStatement().executeQuery("CREATE TABLE demo.tbl(id INT) ENGINE=CnchMergeTree ORDER BY id");
// Query ID: "my-spark-application-3"

示例 2:前缀 + 显式 Query ID

驱动程序将前缀与用户指定的查询ID连接起来。不自动递增。

Properties props = new Properties();
props.setProperty("session_query_id_prefix", "my-spark-application-");

Connection connection = new ByteHouseDriver().connect(jdbcUrl, props);

((ByteHouseConnection) connection).setQueryId("drop-db");
connection.createStatement().executeQuery("DROP DATABASE IF EXISTS demo");
// Query ID: "my-spark-application-drop-db"
((ByteHouseConnection) connection).setQueryId("create-db");
connection.createStatement().executeQuery("CREATE DATABASE IF NOT EXISTS demo");
// Query ID: "my-spark-application-create-db"

配置连接池

ByteHouse 支持通过 HikariCP 和 Druid 进行 JDBC 连接和数据开发。

通过 HikariCP 进行 JDBC 连接

下面举例介绍如何通过 ByteHouse JDBC 驱动程序与 HikariCP 连接。

Maven 依赖

通过 Maven 方式使用 ByteHouse JDBC 驱动时,请在 pom.xml 文件中添加以下依赖项以包含 HikariCP:

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>4.0.3</version>
</dependency>

Gradle 依赖

通过 Gradle 方式使用 ByteHouse JDBC 驱动时,请在 build.gradle 文件中添加以下依赖项以包含 HikariCP:

dependencies {
    implementation 'com.zaxxer:HikariCP:4.0.3'
} 

类名

使用 HikariCP 时,您最常与之交互的类是 HikariDataSource。您可以按照以下示例在 Java 应用程序中配置和使用 HikariCP 来创建 Bytehouse 连接。

连接与查询

可参考下面代码连接至 ByteHouse,使用时注意替换连接语句中的hostportpassworduserdatabasevirtual_warehouse_id 等连接信息字段,获取方式请参见获取 ByteHouse 连接信息

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import java.sql.*;

public class HikariConnection {
    public static Connection getConnectionWithHikariConfig(String host, String port, String apiKey) throws Exception {

        HikariConfig config = new HikariConfig();
        String jdbcURL = String.format("jdbc:bytehouse://%s:%s/?api_key=%s", host, port, apiKey);
        
        // 标准 Hikari 配置
        config.setJdbcUrl(jdbcURL);
        config.setMinimumIdle(5); // 池中的最小空闲连接数
        config.setMaximumPoolSize(20); // 池中的最大连接数
        config.setMaxLifetime(4 * 60 * 1000); // 连接将在 4 分钟后失效(被回收),最长允许(的存活时间)为 5 分钟
        config.setIdleTimeout(2 * 60 * 1000); // 连接闲置 2 分钟后,即符合被驱逐(回收)的条件

        config.setPoolName("BH-Pool");
        config.addDataSourceProperty("secure", "true");
        // config.addDataSourceProperty("virtual_warehouse", {VIRTUAL_WAREHOUSE_ID});

        HikariDataSource hds = new HikariDataSource(config);
        Connection conn = hds.getConnection();
        return conn;
    }

    public static void main(String[] args) {
        String host = "{HOST}";
        String apiKey = "{API_KEY}";
        String port = "19000"; 
        try {
            Connection connection = getConnectionWithHikariConfig(host, port, apiKey);
            createDatabase(connection);
            createTable(connection);
            insertTable(connection);
            insertBatch(connection);
            selectTable(connection);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void createDatabase(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String createDbQuery = "CREATE DATABASE IF NOT EXISTS inventory";
            stmt.execute(createDbQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void createTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {

            String createTableQuery = "CREATE TABLE IF NOT EXISTS inventory.orders\n (" +
                    "OrderID String, OrderName String, OrderPriority Int8)" +
                    " engine = CnchMergeTree() partition by OrderID order by OrderID";
            stmt.execute(
                    createTableQuery
            );
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void insertTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String insertQuery = "INSERT INTO inventory.orders VALUES ('54895','Apple',12)";
            stmt.executeUpdate(
                    insertQuery
            );
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void insertBatch(Connection connection) {
        String insertQuery = "INSERT INTO inventory.orders (OrderID, OrderName, OrderPriority) VALUES (?,'Apple',?)";
        try (PreparedStatement pstmt = connection.prepareStatement(insertQuery)) {
            int insertBatchSize = 10;

            for (int i = 0; i < insertBatchSize; i++) {
                pstmt.setString(1, "ID" + i);
                pstmt.setInt(2, i);
                pstmt.addBatch();
            }
            pstmt.executeBatch();

        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void selectTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String selectTableQuery = "SELECT * FROM inventory.orders";
            ResultSet rs = stmt.executeQuery(selectTableQuery);
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnsNumber = rsmd.getColumnCount();
            while (rs.next()) {
                for (int i = 1; i <= columnsNumber; i++) {
                    if (i > 1) System.out.print(", ");
                    String columnValue = rs.getString(i);
                    System.out.print(columnValue);
                }
                System.out.println();
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
}

通过 Druid 进行 JDBC 连接

您也可以通过阿里巴巴的 Druid 连接池来连接 ByteHouse。

Maven 依赖

通过 Maven 方式使用 ByteHouse JDBC 驱动时,请在 pom.xml 文件中添加以下依赖项以包含 Druid:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.23</version>
</dependency>

Gradle 依赖

通过 Gradle 方式使用 ByteHouse JDBC 驱动时,请在 build.gradle 文件中添加以下依赖项以包含 Druid:

dependencies {
     implementation 'com.alibaba:druid:1.1.23' 
}

类名

在使用 Druid 时,您最常与之交互的类是 DruidDataSource。您可以按照以下示例在Java 应用程序中配置和使用 Druid 来创建 Bytehouse 连接。

连接与查询

可参考下面连接至 ByteHouse,使用时注意替换连接语句中的hostportpassworduserdatabasevirtual_warehouse_id 等连接信息字段,获取方式请参见获取 ByteHouse 连接信息

import com.alibaba.druid.pool.DruidDataSource;
import java.sql.*;
import java.util.Properties;

public class DruidConnection {
    public static Connection getConnectionWithDruidConfig(String host, String port, String apiKey) throws Exception {

        DruidDataSource druidDataSource = new DruidDataSource();
        String jdbcURL = String.format("jdbc:bytehouse://%s:%s/?api_key=%s", host, port, apiKey);
        druidDataSource.setUrl(jdbcURL);
        druidDataSource.setDriverClassName("com.bytedance.bytehouse.jdbc.ByteHouseDriver");
        druidDataSource.setMaxActive(10); // 最大活跃连接数
        druidDataSource.setInitialSize(2); // 初始连接数
        druidDataSource.setMinIdle(2); // 最小空闲连接数
        druidDataSource.setMaxWait(50000); // 获取连接的最大等待时间
        Properties properties = druidDataSource.getConnectProperties();
        properties.setProperty("secure", "true");
        // properties.setProperty("virtual_warehouse", {VIRTUAL_WAREHOUSE_ID});

        druidDataSource.setConnectProperties(properties);
        Connection conn = druidDataSource.getConnection();

        return conn;
    }

    public static void main(String[] args) {
        String host = "{HOST}";
        String apiKey = "{API_KEY}";
        String port = "19000"; 
        try {
            Connection connection = getConnectionWithDruidConfig(host, port, apiKey);
            createDatabase(connection);
            createTable(connection);
            insertTable(connection);
            insertBatch(connection);
            selectTable(connection);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void createDatabase(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String createDbQuery = "CREATE DATABASE IF NOT EXISTS inventory";
            stmt.execute(createDbQuery);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void createTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {

            String createTableQuery = "CREATE TABLE IF NOT EXISTS inventory.orders\n (" +
                    "OrderID String, OrderName String, OrderPriority Int8)" +
                    " engine = CnchMergeTree() partition by OrderID order by OrderID";
            stmt.execute(
                    createTableQuery
            );
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void insertTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String insertQuery = "INSERT INTO inventory.orders VALUES ('54895','Apple',12)";
            stmt.executeUpdate(
                    insertQuery
            );
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void insertBatch(Connection connection) {
        String insertQuery = "INSERT INTO inventory.orders (OrderID, OrderName, OrderPriority) VALUES (?,'Apple',?)";
        try (PreparedStatement pstmt = connection.prepareStatement(insertQuery)) {
            int insertBatchSize = 10;

            for (int i = 0; i < insertBatchSize; i++) {
                pstmt.setString(1, "ID" + i);
                pstmt.setInt(2, i);
                pstmt.addBatch();
            }
            pstmt.executeBatch();

        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public static void selectTable(Connection connection) {
        try (Statement stmt = connection.createStatement()) {
            String selectTableQuery = "SELECT * FROM inventory.orders";
            ResultSet rs = stmt.executeQuery(selectTableQuery);
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnsNumber = rsmd.getColumnCount();
            while (rs.next()) {
                for (int i = 1; i <= columnsNumber; i++) {
                    if (i > 1) System.out.print(", ");
                    String columnValue = rs.getString(i);
                    System.out.print(columnValue);
                }
                System.out.println();
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
}

常见问题

Unsupported or unrecognized SSL message 报错

如果您在使用过程中遇到 Unsupported or unrecognized SSL message 报错,这是 Java 版本过低导致的,Java 1.8.0_261 **** 以下版本会出现此报错。
您可通过以下方式解决:

  • 升级 Java 版本到 Java 11。
  • 如需保留 Java 1.8 环境,可升级至 Java 1.8.0_261 及更高补丁版本解决该问题。

DB::Exception: No local available worker group for vw-xxxx

如果您在使用过程中遇到 DB::Exception: No local available worker group for vw-xxxx 报错,这是计算组尚未启动导致的。
您可通过以下方式解决:
登录 ByteHouse 云数仓版控制台,在计算组页面,查看您使用的计算组是否在 正在运行的状态。

Code: UNAUTHENTICATED

如果您在使用过程中遇到 Exception: unknown error: Code: UNAUTHENTICATED 报错,这可能是 userpassword 配置错误导致的。
您可通过以下方式解决:
再次确认您配置的userpassword是否正确。

DB::Exception: Database xxx.yyy doesn't exist

如果您在使用过程中遇到 DB::Exception: Database xxx.yyy doesn't exist 报错,这可能是数据库名称配置错误导致的。
您可通过以下方式解决:
请确认连接信息中配置的数据库名称是否正确。

Exception: No appropriate protocol

如果您在使用过程中遇到 Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) 报错,这可能是TLS版本不兼容导致的。
您可通过以下方式解决:
请在连接 URL 后面增加一个参数:enabledTLSProtocols=TLSv1.2,TLSv1.3
举例如下:

String url = String.format("jdbc:bytehouse://%s:%d/%s?enabledTLSProtocols=TLSv1.2,TLSv1.3", host, port, database);
最近更新时间:2025.10.22 19:18:52
这个页面对您有帮助吗?
有用
有用
无用
无用