You need to enable JavaScript to run this app.
导航
MySQL JDBC Driver
最近更新时间:2025.11.13 16:32:03首次发布时间:2024.08.01 20:24:06
复制全文
我的收藏
有用
有用
无用
无用

您可以通过开源的 MySQL JDBC 驱动程序连接到 ByteHouse 云数仓版。

环境要求

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

推荐版本

MySQL JDBC Driver 版本: 推荐使用 v8.3.0 及以上版本。

使用限制
  • 暂时不支持 ByteHouse 的 JSONB、BitMap64 类型。
  • 不支持设置 query ID。
  • 如果您在使用过程中遇到其他未知限制,请联系 ByteHouse 团队处理。

安装驱动

本地安装

请单击前往 MySQL Connector 页面,下载 MySQL JDBC Driver v8.3.0。

添加为 Maven 依赖

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

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.3.0</version>
</dependency>

获取 ByteHouse 连接信息

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

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

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

IAM 用户

参数

配置说明

host

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

port

配置为固定值 3306。

user & password

使用 API Key 作为 user 和 password。获取 API Key 请参见获取 API Key

  • user:为 API Key 的前半部分,比如获取的 API Key 为 xxxx.yyyy,则 user 需填写 xxxx
  • password:为 API Key 的前半部分,比如获取的 API Key 为 xxxx.yyyy,则 password 需填写 yyyy

database

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

virtual_warehouse_id

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

数据库用户

参数

配置说明

host

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

port

固定为 3306。

user & password

  • user 配置为 {accountID_or_accountName}::{username}[::{envID}],详情请参见步骤三:获取 ByteHouse 连接串信息
    • {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_id

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

基本用法

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

  • 超时时间配置:connect_timeout 默认为 0s,socketTimeout 默认为 0s。
  • 默认不支持 keepAlive,如需使用该功能,需新建 KeepAliveMysqlSocketFactory 类,可参考配置 KeepAlive 章节配置,该功能需使用 JDK11。

连接信息

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

使用 Propertities 配置连接

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

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

        // 通过 properties 设置一些链接的基本参数
        String url = String.format("jdbc:mysql://%s:%d", host, port);
        Properties properties = new Properties();
        properties.setProperty("useSSl", "true");
        properties.setProperty("verifyServerCertificate", "false");
        properties.setProperty("enabledTLSProtocols", "TLSv1.2");
        properties.setProperty("user", user);
        properties.setProperty("password", password);
        properties.setProperty("database", database);
        // 建议添加以下参数,可提高性能
        // 默认情况下,MySQL 的 prearestatement 在执行 insert batch 时,会将批量数据拆分为单条并通过 insert 语句逐行执行,
        // 添加以下参数后,驱动会将批量数据拼接成一条 SQL 语句并执行,提高查询效率
        properties.setProperty("rewriteBatchedStatements", "true");
        properties.setProperty("useServerPrepStmts", "false");
        
        Connection conn = null;
        Statement initStatement = null;
        try {
            conn = DriverManager.getConnection(url, properties);
            initStatement = conn.createStatement();
            initStatement.execute(String.format("SET virtual_warehouse='%s'", virtual_warehouse_id)); // 指定特定计算组
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (initStatement != null) initStatement.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

使用 URL 的 param 配置连接

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

public class CKJDBC {
    public static void main(String[] args) {
        String host = "{Host}";
        int port = 3306;
        String virtual_warehouse_id = "{VIRTUAL_WAREHOUSE_ID}";
        String password = "{Password}";
        String user = "{User}";
        String database = "{Database}";
        
        String url = String.format("jdbc:mysql://%s:%d/?useSSl=true&verifyServerCertificate=false&enabledTLSProtocols=TLSv1.2&user=%s&password=%s&database=%s&rewriteBatchedStatements=true&useServerPrepStmts=false", // 建议使用 rewriteBatchedStatements=true&useServerPrepStmts=false 来提高批量插入效率
                host, port, user, password, database);

        Connection conn = null;
        Statement initStatement = null;
        try {
            conn = DriverManager.getConnection(url, properties);
            initStatement = conn.createStatement();
            initStatement.execute(String.format("SET virtual_warehouse='%s'", virtual_warehouse_id)); // 指定特定计算组
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (initStatement != null) initStatement.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

配置 KeepAlive

如需使用 keepAlive 功能,请使用 JDK 11,执行以下代码配置并启用。

  1. 继承 MySQL 的 StandardSocketFactory 类。

    package com.bytehouse.factory;
    
    import com.mysql.cj.conf.PropertySet;
    import com.mysql.cj.protocol.StandardSocketFactory;
    import jdk.net.ExtendedSocketOptions;
    import java.net.Socket;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class KeepAliveMysqlSocketFactory extends StandardSocketFactory {
    
        private static final Logger LOG = Logger.getLogger(KeepAliveMysqlSocketFactory.class.getName());
    
        // TCP Keep-Alive parameter(unit:second)
        private static final int KEEPALIVE_IDLE = 60;
        private static final int KEEPALIVE_INTERVAL = 30;
        private static final int KEEPALIVE_COUNT = 60;
    
        @Override
        public Socket createSocket(PropertySet props)  {
            Socket sock = super.createSocket(props);
            configureKeepAlive(sock);
            return sock;
        }
    
        private void configureKeepAlive(Socket sock) {
            try {
                // 启用 Keep-Alive
                sock.setKeepAlive(true);
    
                // 设置 TCP_KEEPIDLE (例如,60 秒)
                sock.setOption(ExtendedSocketOptions.TCP_KEEPIDLE, KEEPALIVE_IDLE);
    
                // 设置 TCP_KEEPINTVL (例如, 30 秒)
                sock.setOption(ExtendedSocketOptions.TCP_KEEPINTERVAL, KEEPALIVE_INTERVAL);
    
                // 设置 TCP_KEEPCNT (例如, 5 probes)
                sock.setOption(ExtendedSocketOptions.TCP_KEEPCOUNT, KEEPALIVE_COUNT);
    
                LOG.info("TCP keep-alive options set successfully.");
            } catch (Exception e) {
                LOG.log(Level.WARNING, "can not configure Keep-Alive", e);
            }
        }
    
    }
    
  2. 在连接 URL 中增加自定义参数 Factory。

    jdbc:mysql://<host>:3306/<database>?socketFactory=com.bytehouse.factory.KeepAliveMysqlSocketFactory
    

创建数据库、表

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

批量写入数据

使用 PreparedStatement 批量数据写入。

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

常见问题

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:mysql://%s:%d/%s?enabledTLSProtocols=TLSv1.2,TLSv1.3", host, port, database);