KingbaseES JDBC 深度实战指南(上):从驱动选型到连接管理,夯实国产数据库交互基础

《KingbaseES数据库》本篇文章所属专栏---持续更新中---欢迎订阅!

引言

在国产数据库蓬勃发展的当下,KingbaseES 作为企业级关系型数据库的代表,已广泛应用于金融、政务、能源等关键领域。而 JDBC(Java Database Connectivity)作为 Java 生态连接数据库的 "黄金桥梁",其在 KingbaseES 中的正确使用,直接决定了 Java 应用与数据库交互的效率、安全性与稳定性。

然而,许多开发者在使用 KingbaseES JDBC 时,常面临 "参数配置混乱""大对象处理踩坑""高可用方案落地难" 等问题 ------ 明明遵循了基础流程,却因不了解驱动特性导致性能瓶颈;想实现读写分离减轻主库压力,却因参数配置不当引发数据一致性问题;处理 BLOB/CLOB 大对象时,又因兼容模式差异导致数据丢失...... 这些问题的根源,往往是对 KingbaseES JDBC 的核心特性、接口设计与实战细节缺乏系统认知。

下面我将基于官方文档,拒绝 "泛泛而谈",聚焦 "实战落地":从驱动包选型、连接建立的底层逻辑,到语句对象的性能优化技巧;从大对象处理的兼容模式差异,到事务管理与元数据应用的深度细节;再到读写分离、高可用配置的完整方案,每一个知识点均对应文档中的核心定义,每一段代码均源自官方示例的优化延伸。

无论是刚接触 KingbaseES 的新手,还是需要解决复杂场景的资深开发者,都能通过本文掌握 Java 与 KingbaseES 高效交互的 "底层逻辑" 与 "实战技巧",真正解锁国产数据库与 Java 生态融合的核心能力。


一、JDBC 与 KingbaseES JDBC 概述

1.1 JDBC 简介

JDBC 是 Java 语言中用于连接和操作关系型数据库的标准 API,它基于 X/Open SQL 调用级接口(CLI)制定,为开发者提供了一套统一的接口来访问不同厂商的数据库。JDBC 4.0 版本符合 SQL 2003 标准,通过java.sqljavax.sql两个核心包,定义了包括驱动程序、连接、语句、结果集等在内的一系列接口和类,数据库厂商只需实现这些接口,就能为 Java 应用提供数据库连接服务。

简单来说,JDBC 就像是一座 "桥梁",一边连接着 Java 应用程序,另一边连接着各种关系型数据库,让 Java 代码能够轻松地与数据库进行数据交互,比如执行 SQL 语句、获取查询结果等。

1.2 KingbaseES JDBC 简介

KingbaseES JDBC 提供了名为kingbase8jdbc的 JDBC 驱动程序,它全面支持 SUN JDBC 3.0 标准,并部分支持 JDBC 4.0 API 标准。通过 KingbaseES JDBC 提供的接口对象,Java 应用程序可以完成与 KingbaseES 数据库的连接建立、SQL 语句执行、结果获取、事务管理以及连接关闭等一系列操作。

KingbaseES JDBC 主要实现了 JDBC 标准中的多个核心接口,这些接口涵盖了数据库交互的各个关键环节,具体如下表所示:

接口类别 具体接口 主要功能
驱动与连接相关 java.sql.Driver 用于注册驱动并创建数据库连接
java.sql.Connection 代表与数据库的连接,用于创建语句对象、管理事务等
javax.sql.DataSource 提供另一种获取数据库连接的方式,支持连接池等特性
语句对象相关 java.sql.Statement 用于执行简单的 SQL 语句(无参数)
java.sql.PreparedStatement 用于执行预编译的 SQL 语句(支持参数化查询)
java.sql.CallableStatement 用于调用数据库中的存储过程
结果集相关 java.sql.ResultSet 存储 SQL 查询返回的结果数据,支持数据读取和更新
java.sql.ResultSetMetaData 提供结果集的元数据信息,如列名、列类型等
大对象相关 java.sql.Blob 用于处理二进制大对象数据(如图片、音频等)
java.sql.Clob 用于处理字符大对象数据(如大文本)
java.sql.SQLXML 用于处理 XML 类型的数据
事务相关 java.sql.Savepoint 用于在事务中设置保存点,支持部分回滚
元数据相关 java.sql.DatabaseMetaData 提供数据库的元数据信息,如数据库版本、支持的功能等
java.sql.ParameterMetaData 提供 PreparedStatement 参数的元数据信息,如参数类型、数量等

KingbaseES JDBC 驱动的体系结构如下图所示,清晰地展示了 Java 应用通过 JDBC 驱动与 KingbaseES 数据库之间的交互流程:

从上图可以看出,Java 应用程序首先通过 KingbaseES JDBC Driver 发起数据库操作请求,驱动程序通过 Java Sockets 与 Kingbase 数据库建立通信连接,然后将 SQL 语句传递给数据库的 SQL Engine 或 PL/SQL Engine 进行执行,最终将执行结果通过驱动程序返回给 Java 应用程序。

目前,KingbaseES JDBC 驱动kingbase8jdbc支持在 JDK 1.6 及以上版本的平台上运行,能够满足不同 Java 项目的开发需求。

1.3 KingbaseES JDBC 操作流程

使用 KingbaseES JDBC 在客户端访问和操纵 KingbaseES 数据库中的数据,通常遵循以下固定的操作流程,这一流程确保了数据交互的规范性和高效性:

  1. 建立与数据库的连接:这是所有数据库操作的前提,需要通过指定数据库的 URL、用户名和密码等信息,借助 DriverManager 或 DataSource 方式创建与数据库的连接。
  2. 创建语句对象:根据 SQL 语句的类型和需求,创建对应的 Statement、PreparedStatement 或 CallableStatement 对象,用于发送 SQL 语句到数据库。
  3. 执行查询并返回结果集对象:通过语句对象执行 SQL 查询语句,获取包含查询结果的数据集合,即 ResultSet 对象。
  4. 处理结果集对象:遍历 ResultSet 对象,读取其中的数据并进行相应的业务处理,如数据展示、数据计算等;如果是更新操作(如 INSERT、UPDATE、DELETE),则获取更新的行数等执行结果。
  5. 关闭结果集和语句对象:在完成结果集处理后,及时关闭 ResultSet 和 Statement 对象,释放相关的 JDBC 资源,避免资源泄漏。
  6. 关闭与数据库的连接:在所有数据库操作完成后,关闭与数据库的连接,释放数据库连接资源,提高数据库的并发处理能力。

下面通过一个简单的流程图,直观地展示这一操作流程:


二、KingbaseES JDBC 驱动包与版本信息

2.1 JDBC 驱动包选择

为了确保 Java 应用能够正常连接和操作 KingbaseES 数据库,需要选择合适的 JDBC 驱动包。KingbaseES 提供了不同版本的 JDBC 驱动包,分别对应不同的 JDK 最低支持版本,开发者可以根据项目所使用的 JDK 版本进行选择,具体如下表所示:

驱动包名称 支持最低 JDK 版本 适用场景
kingbase8-9.0.0.jre6.jar JDK 1.6 适用于使用 JDK 1.6 版本开发的 Java 项目
kingbase8-9.0.0.jre7.jar JDK 1.7 适用于使用 JDK 1.7 版本开发的 Java 项目
kingbase8-9.0.0.jar JDK 1.8 适用于使用 JDK 1.8 及以上版本开发的 Java 项目

这些 JDBC 驱动程序默认存放在 KingbaseES 数据库安装程序目录的 JDBC 文件夹内。在实际项目中,如果需要将现有 Oracle 数据库的 JDBC 驱动替换为 KingbaseES 的 JDBC 驱动,只需将 Oracle 的 JDBC 驱动程序文件替换为上述对应的 KingbaseES JDBC 驱动包,并修改数据库连接字符串即可,极大地降低了项目迁移的成本。

2.2 Maven 项目依赖配置

在 Maven 项目中,不需要手动下载和导入 JDBC 驱动包,只需在项目的pom.xml文件中添加相应的依赖配置,Maven 会自动从中央仓库下载并管理驱动包。根据项目所使用的 JDK 版本,可选择以下对应的依赖配置:

2.2.1 支持 JDK 1.8 及以上版本
XML 复制代码
<!-- 最低可支持JDK1.8 -->
<dependency>
    <groupId>cn.com.kingbase</groupId>
    <artifactId>kingbase8</artifactId>
    <version>9.0.0</version>
</dependency>
2.2.2 支持 JDK 1.7 版本
XML 复制代码
<!-- 最低可支持JDK1.7 -->
<dependency>
    <groupId>cn.com.kingbase</groupId>
    <artifactId>kingbase8</artifactId>
    <version>9.0.0.jre7</version>
</dependency>
2.2.3 支持 JDK 1.6 版本
XML 复制代码
<!-- 最低可支持JDK1.6 -->
<dependency>
    <groupId>cn.com.kingbase</groupId>
    <artifactId>kingbase8</artifactId>
    <version>9.0.0.jre6</version>
</dependency>
2.2.4 国密算法依赖(可选)

如果项目中需要使用 sm3、scram - sm3 或者 sm4 等国密算法进行数据加密和身份认证,还需要在pom.xml文件中额外添加如下依赖,以提供国密算法支持:

XML 复制代码
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.80</version>
</dependency>
2.3 获取 KingbaseES JDBC Driver 版本信息

在开发和维护过程中,有时需要获取 KingbaseES JDBC Driver 的版本信息,以便确认驱动版本是否符合项目需求或排查版本兼容性问题。KingbaseES 提供了三种获取 JDBC 驱动版本信息的方法,以下以kingbase8-9.0.0.jar驱动包为例进行介绍:

2.3.1 直接查看相关文件

首先找到$KINGBASE_HOME/Interface/jdbc/kingbase8-9.0.0.jar文件(其中$KINGBASE_HOME为 KingbaseES 的安装路径),然后使用压缩软件(如 WinRAR、7 - Zip 等)打开该 JAR 包,进入META-INF目录,找到MANIFEST.MF文件并打开。在该文件中,通常会包含 JDBC 驱动的版本信息,如Implementation-Version等字段所对应的值,通过这些字段即可获取驱动的版本信息。

2.3.2 利用命令行方式

打开操作系统的命令行终端(Windows 系统为命令提示符或 PowerShell,Linux 系统为终端),进入到$KINGBASE_HOME/Interface/jdbc目录下,然后执行以下命令:

bash 复制代码
java -jar kingbase8-9.0.0.jar -v

执行该命令后,命令行终端会输出 KingbaseES JDBC Driver 的版本信息,包括版本号、构建时间等详细内容,开发者可以直接从输出结果中获取所需的版本信息。

2.3.3 利用 Java 程序

通过编写 Java 程序,调用java.sql.DatabaseMetaData接口中的getDriverVersion()方法,也可以获取 KingbaseES JDBC Driver 的版本信息。以下是完整的 Java 程序示例:

java 复制代码
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;

public class GetJdbcDriverVersion {
    public static void main(String[] args) {
        // 数据库连接信息
        String url = "jdbc:kingbase8://localhost:54321/testdb"; // 数据库URL,testdb为数据库名
        String user = "system"; // 数据库用户名
        String password = "manager"; // 数据库密码

        Connection conn = null;
        try {
            // 加载JDBC驱动
            Class.forName("com.kingbase8.Driver");
            // 建立数据库连接
            conn = DriverManager.getConnection(url, user, password);
            // 获取数据库元数据
            DatabaseMetaData metaData = conn.getMetaData();
            // 获取JDBC驱动版本信息
            String driverVersion = metaData.getDriverVersion();
            System.out.println("KingbaseES JDBC Driver Version: " + driverVersion);
        } catch (ClassNotFoundException e) {
            System.out.println("加载JDBC驱动失败:" + e.getMessage());
        } catch (SQLException e) {
            System.out.println("数据库操作异常:" + e.getMessage());
        } finally {
            // 关闭数据库连接
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    System.out.println("关闭数据库连接失败:" + e.getMessage());
                }
            }
        }
    }
}

在上述代码中,首先通过Class.forName("com.kingbase8.Driver")加载 KingbaseES JDBC 驱动,然后使用DriverManager.getConnection()方法建立与数据库的连接,接着通过Connection对象的getMetaData()方法获取DatabaseMetaData对象,最后调用getDriverVersion()方法获取并打印 JDBC 驱动的版本信息。运行该程序,即可在控制台输出 KingbaseES JDBC Driver 的版本信息。


三、JDBC 建立与关闭数据库连接

建立与数据库的连接是进行所有数据库操作的基础,KingbaseES JDBC 提供了两种常用的建立数据库连接的方法:通过DriverManager和通过DataSource。同时,在完成数据库操作后,及时关闭连接以释放资源也至关重要。

3.1 使用 DriverManager 建立连接

DriverManager是 JDBC 中的一个重要类,它负责管理已注册的 JDBC 驱动程序,并根据数据库 URL 找到合适的驱动程序来建立与数据库的连接。

3.1.1 加载 JDBC 驱动

在使用DriverManager建立数据库连接之前,需要先加载 KingbaseES 的 JDBC 驱动。有两种常见的加载方式:

  • 使用Class.forName()方法:
java 复制代码
try {
    Class.forName("com.kingbase8.Driver");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
    // 处理驱动加载失败的情况,如提示用户检查驱动包是否正确导入等
}

这种方法通过反射机制加载驱动类,当加载com.kingbase8.Driver类时,该类会在静态代码块中自动向DriverManager注册自身,从而完成驱动的注册。

  • 使用DriverManager.registerDriver()方法:
java 复制代码
try {
    DriverManager.registerDriver(new com.kingbase8.Driver());
} catch (SQLException e) {
    e.printStackTrace();
    // 处理驱动注册失败的情况
}

这种方法直接创建com.kingbase8.Driver对象,并将其注册到DriverManager中。

在实际开发中,推荐使用第一种方法(Class.forName())来加载驱动,因为它更加灵活,且避免了直接依赖驱动类的具体实现。

3.1.2 建立数据库连接

加载驱动后,就可以通过DriverManager.getConnection()方法建立与 KingbaseES 数据库的连接。该方法提供了三种重载形式,以适应不同的参数传递方式:

  • getConnection(String url, String user, String password):直接传递数据库 URL、用户名和密码。
java 复制代码
String url = "jdbc:kingbase8://localhost:54321/testdb"; // 数据库URL
String user = "system"; // 用户名
String password = "manager"; // 密码
try {
    Connection conn = DriverManager.getConnection(url, user, password);
    // 连接建立成功,后续可进行数据库操作
} catch (SQLException e) {
    e.printStackTrace();
    // 处理连接建立失败的情况,如检查URL、用户名、密码是否正确,数据库服务是否正常运行等
}
  • getConnection(String url, java.util.Properties info):通过Properties对象传递连接属性,包括用户名、密码等。
java 复制代码
String url = "jdbc:kingbase8://localhost:54321/testdb";
Properties info = new Properties();
info.put("user", "system"); // 设置用户名
info.put("password", "manager"); // 设置密码
try {
    Connection conn = DriverManager.getConnection(url, info);
    // 连接建立成功
} catch (SQLException e) {
    e.printStackTrace();
}

这种方式适用于需要传递较多连接属性的场景,除了用户名和密码,还可以设置其他连接参数,如字符编码、事务隔离级别等。

  • getConnection(String url):将用户名和密码包含在 URL 中传递。
java 复制代码
String url = "jdbc:kingbase8://localhost:54321/testdb?user=system&password=manager";
try {
    Connection conn = DriverManager.getConnection(url);
    // 连接建立成功
} catch (SQLException e) {
    e.printStackTrace();
}

这种方式将连接参数直接拼接在 URL 中,虽然使用简单,但安全性较低,不推荐在生产环境中使用,尤其是当密码包含特殊字符时,可能会导致 URL 解析错误。

3.1.3 数据库 URL 格式

KingbaseES JDBC 支持多种数据库 URL 格式,以适应不同的网络环境和配置需求,具体格式如下:

  1. jdbc:kingbase8:database:这种格式适用于数据库服务器与客户端在同一台机器上(即localhost),且使用默认端口号(KingbaseES 服务器的默认端口号为 54321)的情况,其中database为数据库名。例如:jdbc:kingbase8:testdb,表示连接本地默认端口上的testdb数据库。

  2. jdbc:kingbase8://host/database:指定数据库服务器的主机名(或 IP 地址)host和数据库名database,使用默认端口号。例如:jdbc:kingbase8://192.168.1.100/testdb,表示连接192.168.1.100主机上默认端口的testdb数据库。

  3. jdbc:kingbase8://host:port/database:指定数据库服务器的主机名host、端口号port和数据库名database。这是最常用的格式,能够精确地定位到目标数据库。例如:jdbc:kingbase8://192.168.1.100:54322/testdb,表示连接192.168.1.100主机上54322端口的testdb数据库。

  4. jdbc:kingbase8://host:port/database?para1=val1&para2=val2...:在基本 URL 的基础上,通过查询参数的形式设置额外的连接属性,如字符编码、超时时间等。例如:jdbc:kingbase8://localhost:54321/testdb?clientEncoding=UTF-8&loginTimeout=10,表示连接本地54321端口的testdb数据库,设置客户端编码为UTF-8,登录超时时间为 10 秒。

如果数据库服务器的主机地址是 IPv6 地址,则必须用中括号将地址括起来,格式如下:jdbc:kingbase8://[IPv6host]:port/database?para1=val1&para2=val2...例如:jdbc:kingbase8://[2021:0:0:0:0:0:0:50]:54321/testdb。需要注意的是,如果使用了 Socks 代理,此处 IPv6 地址需要使用冒分十六进制表示法(如上述示例),不能使用 0 位压缩表示法(如2021::50)。

3.1.4 处理 URL 中的特殊字符

当数据库连接 URL 中包含%?&/等特殊字符时,会对 JDBC 解析连接串造成影响,导致连接失败。为了解决这个问题,可以采用以下三种方法:

  • 使用Properties对象:将连接属性(如用户名、密码、数据库名等)存储在Properties容器中,然后调用getConnection(String url, Properties props)方法建立连接。使用这种方法,连接属性中的特殊字符不需要做任何处理。但需要注意的是,数据库名称必须存储在 URL 中,所以这种方法不能处理数据库名称中含有特殊字符的情况。

示例代码:

java 复制代码
String url = "jdbc:kingbase8://localhost:54321/testdb"; // 数据库名testdb无特殊字符
Properties props = new Properties();
props.put("user", "user%name"); // 用户名包含特殊字符%
props.put("password", "pass?word"); // 密码包含特殊字符?
try {
    Connection conn = DriverManager.getConnection(url, props);
    // 连接建立成功
} catch (SQLException e) {
    e.printStackTrace();
}
  • 使用转义字符处理过的 URL:URL 的词法规则要求一些特殊字符必须经过转义才能被正确识别。KingbaseES JDBC 使用URLEncoder.encode(String arg1, System.getProperty("file.encoding"))方法对特殊字符进行转义,其中arg1为待转义的连接属性值。

URLEncoder的转义规则如下:

  • 字母数字字符(azAZ09)保持不变。
  • 特殊字符.-*_保持不变。
  • 空格字符转换为一个加号+
  • 所有其他字符都是不安全的,首先使用相应平台的默认编码机制将它们转换为一个或多个字节,然后每个字节用一个包含 3 个字符的字符串%xy表示,其中xy为该字节的两位十六进制表示形式。

示例代码:

java 复制代码
import java.net.URLEncoder;

public class UrlEscapeExample {
    public static void main(String[] args) throws Exception {
        String user = "user%name";
        String password = "pass?word";
        // 对用户名和密码进行转义
        String encodedUser = URLEncoder.encode(user, System.getProperty("file.encoding"));
        String encodedPassword = URLEncoder.encode(password, System.getProperty("file.encoding"));
        // 构建转义后的URL
        String url = "jdbc:kingbase8://localhost:54321/testdb?user=" + encodedUser + "&password=" + encodedPassword;
        try {
            Connection conn = DriverManager.getConnection(url);
            // 连接建立成功
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • 使用配置文件(适用于连接参数较多的场景):当连接参数较多时,可以将连接参数配置在一个配置文件中,然后在连接串中通过ConfigurePath参数指定配置文件的路径。这种方法可以避免在 URL 中直接拼接大量参数,同时也能处理参数中的特殊字符。

示例:

  • 配置文件jdbc.conf内容:

plaintext

复制代码
user=user%name
password=pass?word
clientEncoding=UTF-8
  • 连接 URL:jdbc:kingbase8://localhost:54321/testdb?ConfigurePath=jdbc.conf
  • 建立连接的代码:
java 复制代码
String url = "jdbc:kingbase8://localhost:54321/testdb?ConfigurePath=jdbc.conf";
try {
    Connection conn = DriverManager.getConnection(url);
    // 连接建立成功
} catch (SQLException e) {
    e.printStackTrace();
}
3.2 使用 DataSource 建立连接

DataSource接口是 JDBC 3.0 规范中定义的另一种获取数据库连接的方法,它相比DriverManager具有更多的优势,如支持连接池、分布式事务等特性,同时提高了应用程序的可移植性。

使用DataSource进行数据库连接时,应用程序通过一个逻辑名称(如 JNDI 名称)获取DataSource对象,该对象由应用服务器或连接池管理工具创建和配置,包含了数据库连接的相关信息。如果数据源的信息(如数据库地址、端口号等)发生变化,只需修改DataSource对象的配置,而不需要修改应用程序代码,极大地简化了应用程序的维护工作。

DataSource接口的实现可以分为两种:基本实现和支持连接池的实现。在基本实现中,每个Connection对象对应一个物理的数据库连接,当关闭Connection对象时,物理连接也会随之关闭;而在支持连接池的实现中,DataSource会维护一个连接池,Connection对象关闭后会被放回连接池,供其他应用程序复用,从而提高数据库的访问效率。

KingbaseES JDBC 在KBSimpleDataSource类中实现了基本的DataSource接口,在Jdbc3PoolingDataSource类中实现了具有连接池功能的DataSource接口。下面分别介绍它们的使用方法。

3.2.1 使用 KBSimpleDataSource(不使用连接池)

使用KBSimpleDataSource建立数据库连接的步骤如下:

  • 创建 KBSimpleDataSource 对象
java 复制代码
KBSimpleDataSource ds = new KBSimpleDataSource();
  • 初始化连接属性KBSimpleDataSource提供了一系列setXXX()方法用于设置数据库连接的属性,包括数据库名、密码、端口号、服务器地址、用户名等标准属性。
java 复制代码
ds.setDatabaseName("testdb"); // 设置数据库名
ds.setPassword("manager"); // 设置密码
ds.setPortNumber(54321); // 设置端口号
ds.setServerName("localhost"); // 设置服务器地址(主机名或IP)
ds.setUser("system"); // 设置用户名
  • 获取数据库连接 :通过getConnection()方法获取数据库连接,该方法有两种重载形式:

getConnection():如果已经通过setUser()setPassword()方法设置了用户名和密码,可直接调用此方法获取连接。

java 复制代码
try {
    Connection conn = ds.getConnection();
    // 连接建立成功,进行数据库操作
} catch (SQLException e) {
    e.printStackTrace();
}

getConnection(String user, String password):如果没有提前设置用户名和密码,或需要使用不同的用户身份连接数据库,可调用此方法并传递用户名和密码。

java 复制代码
try {
    Connection conn = ds.getConnection("system", "manager");
    // 连接建立成功
} catch (SQLException e) {
    e.printStackTrace();
}
3.2.2 使用 Jdbc3PoolingDataSource(使用连接池)

Jdbc3PoolingDataSource是支持连接池功能的DataSource实现类,使用它可以提高数据库连接的复用率,减少连接建立和关闭的开销,从而提高应用程序的性能。

使用Jdbc3PoolingDataSource建立数据库连接的步骤如下:

  • 创建 Jdbc3PoolingDataSource 对象
java 复制代码
Jdbc3PoolingDataSource ds = new Jdbc3PoolingDataSource();
  • 设置连接池和数据库连接属性:除了设置数据库连接的基本属性(如数据库名、用户名、密码等)外,还需要设置连接池的相关属性,如最大连接数、初始连接数等。
java 复制代码
// 设置数据源名称(可选,用于标识数据源)
ds.setDataSourceName("A Data Source");
// 设置数据库名
ds.setDatabaseName("testdb");
// 设置用户名
ds.setUser("system");
// 设置密码
ds.setPassword("manager");
// 设置最大连接数,即连接池中最多可容纳的连接数量
ds.setMaxConnections(10);
// 设置初始连接数,即连接池初始化时创建的连接数量
ds.setInitialConnections(10);
// 设置数据库服务器端口号
ds.setPortNumber(54321);
// 设置数据库服务器地址
ds.setServerName("localhost");
  • 获取数据库连接 :与KBSimpleDataSource类似,通过getConnection()方法获取连接。
java 复制代码
try {
    Connection conn = ds.getConnection();
    // 进行数据库操作,如创建Statement对象、执行SQL语句等
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM table1");
    // 处理结果集
    while (rs.next()) {
        // 读取数据
        System.out.println(rs.getString(1));
    }
    // 关闭结果集、语句对象和连接(连接关闭后会放回连接池)
    rs.close();
    stmt.close();
    conn.close();
} catch (SQLException e) {
    e.printStackTrace();
}
  • 关闭连接池:在应用程序退出或不再需要连接池时,应关闭连接池,释放所有连接资源。
java 复制代码
ds.close();

需要注意的是,连接池只需创建一次,通常在应用程序初始化时创建;在应用程序退出时,再执行关闭连接池的操作,以确保资源的正确释放。

3.2.3 使用 DataSource 结合 JNDI

在 J2EE 应用中,通常会使用 JNDI(Java Naming and Directory Interface)来管理DataSource对象,使得应用程序可以通过逻辑名称查找DataSource,而不需要硬编码数据库连接信息,提高了应用程序的灵活性和可维护性。

使用DataSource结合 JNDI 建立数据库连接的步骤如下:

  • 建立数据源并绑定到 JNDI
java 复制代码
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.util.Hashtable;
import com.kingbase8.ds.KBSimpleDataSource;

public class JndiDataSourceBinding {
    public static void main(String[] args) {
        try {
            // 创建KBSimpleDataSource对象并设置连接属性
            KBSimpleDataSource ds = new KBSimpleDataSource();
            ds.setDatabaseName("testdb");
            ds.setUser("system");
            ds.setPassword("manager");
            ds.setPortNumber(54321);
            ds.setServerName("localhost");

            // 配置JNDI环境
            Hashtable<String, String> env = new Hashtable<>();
            // 设置JNDI初始化上下文工厂
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
            // 设置JNDI提供者URL(需要在本地创建对应的目录,如D:/job/jndi)
            env.put(Context.PROVIDER_URL, "file:/D:/job/jndi");

            // 创建InitialContext对象
            Context ctx = new InitialContext(env);

            // 将DataSource对象绑定到JNDI,绑定名称为"DataSource"
            ctx.rebind("DataSource", ds);

            System.out.println("DataSource绑定到JNDI成功!");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
}

在运行上述代码之前,需要先从http://java.sun.com下载fscontext.jarproviderutil.jar两个 JAR 文件,并添加到项目的类路径中,因为com.sun.jndi.fscontext.RefFSContextFactory类位于这两个 JAR 文件中。

  • 通过 JNDI 查找 DataSource 并获取连接
java 复制代码
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;

public class JndiDataSourceLookup {
    public static void main(String[] args) {
        try {
            // 配置JNDI环境(与绑定数据源时的环境配置一致)
            Hashtable<String, String> env = new Hashtable<>();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
            env.put(Context.PROVIDER_URL, "file:/D:/job/jndi");

            // 创建InitialContext对象
            Context ctx = new InitialContext(env);

            // 通过JNDI名称查找DataSource对象
            DataSource ds = (DataSource) ctx.lookup("DataSource");

            // 获取数据库连接
            Connection conn = ds.getConnection();

            // 执行SQL查询
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM table1");

            // 处理结果集
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name"));
            }

            // 关闭资源
            rs.close();
            stmt.close();
            conn.close();
            ctx.close();
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

通过 JNDI 管理DataSource,使得应用程序可以在不修改代码的情况下,灵活地切换数据源或修改数据库连接配置,非常适合在大型企业级应用中使用。

3.3 关闭数据库连接

在完成所有数据库操作后,必须及时关闭数据库连接,以释放数据库资源,避免资源泄漏,提高数据库的并发处理能力。关闭数据库连接非常简单,只需调用Connection对象的close()方法即可:

java 复制代码
if (conn != null) {
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
        // 处理关闭连接失败的情况,如记录日志等
    }
}

需要注意的是,在关闭连接之前,应先关闭通过该连接创建的ResultSetStatement(或PreparedStatementCallableStatement)对象,以确保所有相关资源都能被正确释放。通常的资源关闭顺序为:先关闭ResultSet,再关闭Statement,最后关闭Connection

示例代码:

java 复制代码
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;

try {
    // 建立连接、创建语句对象、执行查询并处理结果集
    conn = DriverManager.getConnection(url, user, password);
    stmt = conn.createStatement();
    rs = stmt.executeQuery("SELECT * FROM table1");
    while (rs.next()) {
        // 处理数据
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    // 关闭结果集
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 关闭语句对象
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    // 关闭连接
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

在 Java 7 及以上版本中,可以使用 try-with-resources 语句来自动关闭资源,无需手动调用close()方法,简化了代码的编写,同时也能确保资源的正确释放。示例代码如下:

java 复制代码
try (Connection conn = DriverManager.getConnection(url, user, password);
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery("SELECT * FROM table1")) {
    // 处理结果集
    while (rs.next()) {
        // 读取数据
    }
} catch (SQLException e) {
    e.printStackTrace();
}

在 try-with-resources 语句中,ConnectionStatementResultSet对象会在 try 块执行结束后(无论正常结束还是抛出异常)自动关闭,遵循 "声明的顺序相反" 的关闭顺序,即先关闭ResultSet,再关闭Statement,最后关闭Connection


总结

本篇文章聚焦 "基础能力夯实",系统讲解了三大核心内容:

  1. JDBC 与 KingbaseES JDBC 概述:明确 JDBC 的标准定位与 KingbaseES JDBC 的接口体系,结合数据库架构图,厘清 Java 应用与 KingbaseES 的交互逻辑;
  2. 驱动包与版本信息:详细说明驱动包的选型规则(按 JDK 版本匹配)、Maven 依赖配置、版本信息获取方法,避免因版本不兼容导致的基础故障;
  3. 数据库连接的建立与关闭 :对比DriverManager(简单场景)与DataSource(连接池 / 企业场景)两种连接方式,详解 URL 格式、特殊字符处理、规范关闭流程,确保连接资源合理使用。

由于全文涵盖 JDBC 全流程实战(从基础到高可用)下一篇我将带你聚焦 "实战进阶",深入讲解 JDBC 连接属性的精细化配置(性能优化、安全加密、高可用)、语句对象(Statement/PreparedStatement/CallableStatement)的实战技巧、结果集处理、大对象操作、事务管理、元数据应用、读写分离与高可用配置等核心内容,帮助开发者从 "会用" 到 "用好" KingbaseES JDBC,真正解锁 Java 与国产数据库的高效交互能力。

相关推荐
安当加密4 天前
通过TDE透明加密实现人大金仓数据库的免改造存储加密方案
数据库·金仓·透明加密
Navicat中国16 天前
Navicat 技术指引 | KingbaseES 逆向工程与正向工程
数据库·database·navicat·建模·金仓·kingbasees
全栈小54 个月前
【数据库】零门槛在线体验KingbaseES平台,SQL Server模式高阶玩法,动态创建数据体验函数、存储过程等功能
数据库·sql server·金仓·kingbasees平台
Joyce.Du2 年前
kingbase配置SSL双向认证
linux·服务器·postgresql·ssl·金仓