PDF文库 - 千万精品文档,你想要的都能搜到,下载即用。

KingbaseES客户端编程接口指南-JDBC.pdf

Heart Att276 页 725.214 KB下载文档
KingbaseES客户端编程接口指南-JDBC.pdfKingbaseES客户端编程接口指南-JDBC.pdfKingbaseES客户端编程接口指南-JDBC.pdfKingbaseES客户端编程接口指南-JDBC.pdfKingbaseES客户端编程接口指南-JDBC.pdfKingbaseES客户端编程接口指南-JDBC.pdf
当前文档共276页 2.88
下载后继续阅读

KingbaseES客户端编程接口指南-JDBC.pdf

KingbaseES 客户端编程接口指南-JDBC 金仓数据库管理系统 KingbaseES 文档版本:V9(V009R001C001B0024) 发布日期:2023 年 10 月 12 日 北京人大金仓信息技术股份有限公司 目 目 录 录 第 1 章 前言 1 1.1 适用读者 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 相关文档 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.3 术语 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.4 手册约定 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 第 2 章 概述 3 2.1 JDBC 介绍 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.2 KingbaseES JDBC 简介 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.3 操作过程 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.4 JDBC 驱动包 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.5 获取 KingbaseES JDBC Driver 版本信息 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 第 3 章 JDBC 建立/关闭连接 7 建立与数据库的连接 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.1.1 使用 DriverManager 连接数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.1.2 JDBC 连接属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.1.3 使用 DataSource 连接数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.1.3.1 使用 DataSource 连接数据库(不使用 JNDI) . . . . . . . . . . . . . . . . . . . . . . 21 3.1.3.2 使用 DataSource 连接数据库(使用 JNDI) . . . . . . . . . . . . . . . . . . . . . . . 22 3.1.3.3 连接池 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 关闭与数据库的连接 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3 JDBC Driver API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4 JDBC Connection API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.5 JDBC DataSource API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.6 JDBC ConnectionPoolDataSource API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.7 JDBC PooledConnection API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.8 JDBC XAConnection API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.9 JDBC XADataSource API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.1 第 4 章 JDBC 创建语句对象 4.1 Statement 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 43 I 目 录 4.2 PreparedStatement 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 4.3 CallableStatement 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 4.4 JDBC Statement API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.5 JDBC PreparedStatement API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.6 JDBC CallableStatement API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 第 5 章 JDBC 查询结果集处理 91 5.1 结果集的读取 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.2 对结果集的更新 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.3 JDBC ResultSet API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 第 6 章 RowId 接口 127 6.1 RowId 接口函数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 6.2 绑定 RowId 参数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 6.3 取 RowId 值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 第 7 章 JDBC 大对象数据处理 134 7.1 大对象数据的读取 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 7.2 大对象数据的更新 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 7.3 JDBC Blob API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 7.4 JDBC Clob API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 7.5 JDBC SQLXML API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 第 8 章 JDBC 事务处理 150 8.1 事务的提交与回滚 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 8.2 JDBC 事务的隔离级别 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 8.3 JDBC Savepoint API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 第 9 章 JDBC 元数据处理 153 9.1 数据库元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 9.2 参数元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 9.3 结果集元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 9.4 数据类型映射表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 9.5 JDBC Databasemetadata API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 9.6 JDBC ParameterMetaData API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 9.7 JDBC ResultSetMetaData API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 第 10 章 JDBC 读写分离 198 10.1 使用读写分离功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 10.2 读写分离一些现象分析 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 第 11 章 JDBC 读写分离最佳实践 201 11.1 读写分离最大性能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 11.2 读写分离(读已提交)最大一致性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 11.3 读写分离(可重复读)最大一致性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 II 目 录 第 12 章 JDBC 高可用最佳实践 206 第 13 章 JDBC 示例说明 208 13.1 DataSource 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 13.2 ConnectionPooling 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 13.3 Statement 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 13.4 PreparedStatement 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 13.5 CallableStatement 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 13.6 ResultSet 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 13.7 BLOB 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 13.8 CLOB 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 13.9 Transaction 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 13.10 DatabaseMetadata 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 13.11 调用存储过程示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 13.12 interval year[(n)] to month 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 13.13 interval day[(n)] to second[(m)] 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 13.14 RowId 示例 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 第 14 章 在应用服务器中配置 JDBC 261 14.1 WebSphere5.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 14.2 Weblogic7.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 14.3 Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 版权声明 270 服务周期承诺 271 III 第 1 章 前言 1 第 章 前言 本文档描述了 KingbaseES 数据库对于 JDBC 兼容的驱动程序,以及 KingbaseES JDBC 驱动程序的使用方法和 配置。 前言部分包含以下主题: • 适用读者 • 相关文档 • 术语 • 手册约定 1.1 适用读者 《KingbaseES JDBC 指南》面向所有使用 KingbaseES 数据库的用户,主要是数据库管理员和 Java 应用程序开 发人员。 1.2 相关文档 有关 JDBC 的更多信息,请参阅以下资源: Java JDBC API 1.3 术语 $KINGBASE_HOME:KingbaseES 的安装路径。 1 第 1 章 前言 1.4 手册约定 本文档中可能出现“注意、提示、警告、另请参阅”等标志,它们所代表的含义如下: 注意: 用于突出重要/关键信息、最佳实践等。 提示: 用于突出小窍门、捷径等。 警告: 用于传递设备或环境安全警示信息,若不避免,可能会导致设备损坏、数据丢失、设备性能降低或其 它不可预知的结果。 另请参阅: 用于突出参考、参阅等。 以下程序代码书写约定适用于本文档: 符号 说明 [] 表示包含一个或多个可选项。不需要输入中括号本身。 {} 表示包含两个以上(含两个)的候选,必须在其中选取一个。不需要输入花括号本身。 | 分割中括号或者花括号中的两个或两个以上选项。不需要输入“|”本身。 ... 表示其之前的元素可以被重复。 斜体 表示占位符或者需要提供特定值的变量。 大写 表示系统提供的元素,以便与用户定义的元素相互区分。除出现在方括号中的元素外,应当按 照顺序逐字输入。当然,部分元素在系统中是大小写不敏感的,因此用户可以根据系统说明以 小写形式输入。 小写 表示由用户提供的元素。 2 第 2 章 概述 2 第 章 概述 • JDBC 介绍 • KingbaseES JDBC 简介 • 操作过程 • JDBC 驱动包 • 获取 KingbaseES JDBC Driver 版本信息 2.1 JDBC 介绍 Java 数据库连接(JDBC)是一种 Java 标准,提供了从 Java 连接到关系型数据库的接口。JDBC 基于 X/Open SQL 调用级接口(CLI)。JDBC 4.0 符合 SQL2003 标准。 JDBC 标准是通过标准 java.sql 接口定义和实现的。数据库厂商能够通过实现和扩展 JDBC 标准,实现自身的 JDBC 驱动程序。 2.2 KingbaseES JDBC 简介 KingbaseES JDBC 提供了 JAVA 的 JDBC 驱动程序 kingbase8jdbc,它支持 SUN JDBC 3.0 和部分 4.0 API 的 标准。通过 JDBC 接口对象,应用程序可以完成与数据库的连接、执行 SQL 语句、从数据库中获取结果、状态及错 误信息、终止事务和连接等操作。 JDBC API 是 JAVA 平台(J2EE 和 J2SE)的一个部分,它由两个包组成:java.sql 和 javax.sql。在 java.sql 和 javax.sql 中包含了多个类和多个标准接口。KingbaseES JDBC 主要实现了这些标准接口,还实现了特定的数据源接 口。 目前 KingbaseES JDBC 实现了的标准接口有: java.sql.Driver java.sql.Connection 3 第 2 章 概述 java.sql.Statement java.sql.PreparedStatement java.sql.CallableStatement java.sql.DatabaseMetaData java.sql.ParameterMetaData java.sql.ResultSet java.sql.ResultMetaData java.sql.Savepoint java.sql.Clob java.sql.Blob java.sql.SQLXML java.sql.Array java.sql.RowId java.sql.Struct javax.sql.DataSource javax.sql.CommonDataSource javax.sql.ConnectionEventListener javax.sql.ConnectionPoolDataSource javax.sql.PooledConnection javax.sql.XAConnection javax.sql.XADataSource 下图展示了 KingbaseES JDBC 与 KingbaseES 数据库的体系结构: 图 2.2.1: JDBC 与 KingbaseES 结构图 本部分介绍了 KingbaseES JDBC 提供的各项功能和具体的使用方法。 kingbase8jdbc 支持 SUN JDBC4.0 标准,运行在 JDK 1.6 及以上平台。 4 第 2 章 概述 2.3 操作过程 在客户端使用 KingbaseES JDBC 来访问和操纵 KingbaseES 数据库中的数据通常包括以下过程: a. 建立与数据库的连接; b. 创建语句对象; c. 执行查询并返回结果集对象; d. 处理结果集对象; e. 关闭结果集和语句对象; f. 关闭与数据库的连接。 2.4 JDBC 驱动包 为了使用 KingbaseES 数据库,我们提供了 KingbaseES JDBC 的驱动包: 驱动包 支持最低版本 kingbase8-9.0.0.jre6.jar JDK1.6 kingbase8-9.0.0.jre7.jar JDK1.7 kingbase8-9.0.0.jar JDK1.8 KingbaseES 的 JDBC 驱动程序存放在数据库安装程序目录的 JDBC 文件夹内,应用程序只需把 Oracle 的 JDBC 驱动程序和数据库连接字符串替换为 KingbaseES 的对应内容即可。 也可以在 maven 项目的 pom.xml 文件中添加依赖, 根据需求选择需要的版本: cn.com.kingbasekingbase89.0.0cn.com.kingbasekingbase89.0.0.jre7 5 第 2 章 概述 cn.com.kingbasekingbase89.0.0.jre6 2.5 获取 KingbaseES JDBC Driver 版本信息 我们有三种方式可以获得 KingbaseES JDBC Driver 版本信息(以 kingbase8-9.0.0.jar 为例): a. 直接查看相关文件: 查看 $KINGBASE_HOME/ Interface/ jdbc/ kingbase8-9.0.0.jar 文件中的 META-INF/ MANIFEST.MF 文件, 可以获得驱动版本信息; b. 利用命令行方式: 进入到 $KINGBASE_HOME/Interface/jdbc 目录下, 在控制台窗口运行 java -jar kingbase89.0.0.jar -v 命令可以查看到驱动版本信息; c. 利用 Java 程序: 通过 java.sql.DatabaseMetaData 接口中的 getDriverVersion() 获取驱动版本信息。 6 第3章 3 第 章 JDBC 建立/关闭连接 JDBC 建立/关闭连接 • 建立与数据库的连接 • 关闭与数据库的连接 • JDBC Driver API • JDBC Connection API • JDBC DataSource API • JDBC ConnectionPoolDataSource API • JDBC PooledConnection API • JDBC XAConnection API • JDBC XADataSource API 3.1 建立与数据库的连接 KingbaseES JDBC 中提供了两种建立数据库连接的方法:通过 DriverManager 和 DataSource。 • 使用 DriverManager 连接数据库 • JDBC 连接属性 • 使用 DataSource 连接数据库 3.1.1 使用 DriverManager 连接数据库 如果应用程序需要通过 KingbaseES JDBC 来访问和操纵 KingbaseES 数据库中的数据,则应在程序开始时先装 载 KingbaseES 的 JDBC,可以使用以下语句完成该项工作: Class.forName("com.kingbase8.Driver"); 或 DriverManager.registerDriver(new com.kingbase8.Driver()); 7 第3章 JDBC 建立/关闭连接 也可以直接通过以下调用来建立连接: Connection con = DriverManager.getConnection(TestUtil.getURL(), TestUtil.getUser(), TestUtil.getPassword()); 注意: forName() 方法可能抛出一个 ClassNotFoundException,所以在程序中需要捕获该异常。 与数据库建立连接的标准方法是调用 DriverManager.getConnection 方法,它有以下三种调用格式: a. getConnection(url, user, password) b. getConnection(url, java.util.Properties) c. getConnection(url) DriverManager 类(即所谓的 JDBC 管理器)将尝试找到可与 URL 所代表的那个数据库进行连接的驱动程序。 DriverManager 类存有已注册的 Driver 类清单,当调用方法 getConnection 时,它将检查清单中的每个驱动程序,直 到找到可与 URL 中指定的数据库进行连接的驱动程序为止。 在 KingbaseES JDBC 中,数据库是用 URL 表示的。目前 KingbaseES JDBC 支持以下几种地址格式: jdbc:kingbase8:database jdbc:kingbase8://host/database jdbc:kingbase8://host:port/database jdbc:kingbase8://host:port/database?para1=val1¶2=val2… 如果 host 是 IPv6 地址,则必须用中括号把地址括起来,如下所示: jdbc:kingbase8://[IPv6host]:port/database?para1=val1¶2=val2… 注意: 如果使用了 Socks 代理,此处 IPv6 地址需要使用冒分十六进制表示法(如:2021:0:0:0:0:0:0:50),不能使用 0 位压缩表示法(如 2021::50)。 这里: host 是数据库服务器的地址,包括域名、主机名、主机的 IP 地址等。缺省是”localhost” port 是数据库服务器监听的端口号。KingbaseES 服务器的缺省端口号:54321; database 是数据库名。 如果连接串中包含 (’%’,’?’,’&’,’/’) 等字符时,会对 JDBC 分析连接串造成影响。解决的办法有以下三种: a. 使用 Properties。 8 第3章 JDBC 建立/关闭连接 将连接属性和其值存储在 Poperties 容器中,并调用 getConnection(String url, Properties props) 方法,获得连 接。使用这种方法,连接属性中的特殊字符不需要做任何处理。但由于数据库名称必须存储在 url 中,所以这 种方法不能处理数据库名称中含有特殊字符的情况。 b. 使用转义字符处理过的 URL。 URL 的词法规则要求一些特殊字符必须经过转义才能被正确的识别。KingbaseES JDBC 使用的转义方法如 下: URLEncoder.encode(String arg1, System.getProperty(”file.encoding”)) 其中 arg1 为各种连接属性值,为待转义字符串。 URLEncoder 的转义规则如下: • 字母数字字符”a” 到”z”、”A” 到”Z” 和”0” 到”9” 保持不变。 • 特殊字符”.”、”-”、”*” 和”_” 保持不变。 • 空格字符” ” 转换为一个加号”+”。 • 所有其他字符都是不安全的,因此首先使用一些编码机制将它们转换为一个或多个字节。然后每个字节用 一个包含 3 个字符的字符串”%xy” 表示,其中 xy 为该字节的两位十六进制表示形式。其编码方式使用相 应平台的默认编码。 另附:SQL Server 2005 的转义规则由于包含特殊字符(如空格、分号和引号), 所以必须转义连接 URL 值的 某些部分。如果这些字符包含在大括号中,则 JDBC 驱动程序将支持对其进行转义。例如:{;} 将转义分号。 转义的值可以包含特殊字符(特别是“=”、“;”、“[]”和空格),但不能包含大括号。应将必须进行转义且 包含大括号的值添加到属性集中。 例 3-1. 建立数据库连接的步骤 下面是通常情况下建立数据库连接所需的所有步骤的示例: Connection con; Class.forName("com.kingbase8.Driver"); String url = "jdbc:kingbase8://localhost:54321/testdb"; con = DriverManager.getConnection(url,"userID","passwd"); 3.1.2 JDBC 连接属性 除了标准的连接参数外,JDBC 驱动程序还提供了一些额外的连接参数去指定一些 JDBC 驱动程序的工作方式。 这些参数或者可以在 connection URL 中设置,或者可以保存在一个 Properties object 中。以下例子分别使用以上两 种方法建立一个不使用转义字符的连接: String url = "jdbc:kingbase8://localhost:54321/testdb"; java.util.Properties info = new java.util.Properties(); info.put ("user", "system"); 9 第3章 JDBC 建立/关闭连接 info.put ("password", "manager"); Connection con = DriverManager.getConnection(url, info); String url = "jdbc:kingbase8://localhost:54321/testdb?user=system&password=manager"; Connection con = DriverManager.getConnection(url); 除以上方法外,当连接参数较多时,也可通过配置文件配置连接参数,此时需在连接串中添加参数 ConfigurePath 来指定配置文件的路径。 以 下 例 子 分 别 使 用 两 种 方 式 来 建 立 读 写 分 离 的 配 置, 以 集 群:node1[192.168.8.128:54321]、 node2[192.168.8.223:54322]、node3[192.168.8.130:54323] 为例: 只用连接串 开启 JDBC 读写分离 一主两备: URL jdbc:kingbase8://192.168.8.128:54321/test?USEDISPATCH=true &SLAVE_ADD=192.168.8.223,192.168.8.130 &SLAVE_PORT=54322,54323 &nodeList=node1,node2,node3 连接串 + 配置文件 开启 JDBC 读写分离 一主两备: URL jdbc:kingbase8://192.168.8.128:54321/test?ConfigurePath=jdbc.conf jdbc.conf 配置文件 USEDISPATCH=true SLAVE_ADD=192.168.8.223,192.168.8.130 SLAVE_PORT=54322,54323 nodeList=node1,node2,node3 在连接中可以额外指定的连接参数如下列各表所示: 表 3.1.1: 协议参数表 参数名称 参 数 值 参数说明 默认值 指定建立连接时采用的通信协议,当前只支持版本 3 null 类型 protocolVersion String 10 第3章 JDBC 建立/关闭连接 表 3.1.2: 预编译缓存控制参数表 参数名称 参 数 值 参数说明 默认值 指定使用哪种模式发送查询给数据库:”simple” 全部语 extended 类型 preferQueryMode String 句只发送 Q 报文,不发送 parse/bind/execute 报文;” extended” 全部语句都发送 parse/bind/execute 报文;” extendedForPrepared” 只有 prepare 语句才发送 parse/ bind/execute 报文;”extendedCacheEveryting” 和”extended” 一样并且缓存每一条语句。 prepareThreshold 指定同一条 prepare 语句执行多少次后才启用服务器端 Integer 5 prepare preparedStatementCacheQueries Integer preparedStatementCacheSizeMiB Integer 指定 prepare 语句的最大缓存数目 256 指定 prepare 语句的缓存最大大小(以兆字节为单位) 5 表 3.1.3: 元信息控制参数表 参数名称 参数值类 参数说明 默认值 型 unknownLength Integer 指定未知长度类型的返回长度 2147483647 databaseMetadataCacheFields Integer 指定数据库元数据的最大缓存数目 65536 databaseMetadataCacheFieldsMiB Integer 指定数据库元数据的缓存最大大小 5 (以兆字节为单位) 表 3.1.4: 性能扩展参数表 参数名称 参 数 值 参数说明 默认值 获取结果集行数的默认值,0 意思是一次获取结果集的 0 类型 defaultRowFetchSize Integer 所有行 disableColumnSanitiser boolean 指定是否启用禁用列名净化的优化器 false reWriteBatchedInserts boolean 指定是否启用优化以重写和折叠批处理的兼容性 IN- false SERT 语句 见续表 11 第3章 JDBC 建立/关闭连接 表 3.1.4 – 续表 参数名称 参 数 值 参数说明 默认值 指定通信传输压缩的比率,取值范围为 0~9 的整数值, 0 类型 zipLevel Integer 0 表示不进行压缩,9 表示最高压缩比率。使用时需 依赖 C 库,通过 java.library.path 指定其路径。Windows 下为 compresskb.dll 和 compresskb.lib(可通过 PATH 指定其路径),Linux 下为 libcompresskb.so(通 过 LD_LIBRARY_PATH 指定其路径)。该功能适用 于网络 IO 为瓶颈(带宽小于 100Mb)的情况。该参数 需要 V8R6C5 以上版本的数据库才能支持。注意:传 输压缩,需要双发压缩和解压协议消息,因此会带来额 外 CPU 开销,如果网络不是瓶颈,那么开启压缩反而 会降低性能。 useFetchSizeInAutoCommit boolean 指定是否在自动提交模式下使用按需执行的功能。使用 false 时需打开服务器自动提交模式下的按需执行功能,同时 指定参数 defaultRowFetchSize optimizeBatchedDML boolean 指定是否开启批量 INSERT、UPDATE、DELETE、 false MERGE 优化,批量是指 JDBC 标准批量处理接口 executeBatch。该参数要求待执行 SQL 必须包含占位 符,同时如果设置了 reWriteBatchedInserts=true 或者 preferQueryMode=simple,那么该参数会被忽略。开启 该参数后,批量执行返回的数组第一个位置为所有影响 行数之和,其余位置为 0 表 3.1.5: 诊断信息参数表 参数名称 参 数 值 参数说明 默认值 类型 loggerLevel String 指 定 日 志 记 录 级 别。 日 志 记 录 级 别 为:” OFF”, ” null 指定日志信息文件的保存路径。可以是相对路径,也可 null WARNING”, ”INFO”, ”DEBUG”, ”TRACE” loggerFile String 以是绝对路径,如果为 null 则不生成日志文件,而是 打印到控制台。如果有指定路径,则只打印到文件。例 如:LogFile=e:\logFile.txt 见续表 12 第3章 JDBC 建立/关闭连接 表 3.1.5 – 续表 参数名称 参 数 值 参数说明 默认值 指定当未显式关闭的连接被垃圾回收时,是否从连接的 false 类型 logUnclosedConnections boolean 打开记录堆栈跟踪泄漏源 logServerErrorDetail boolean 指定是否在错误信息里包含服务器错误的详细信息 true 表 3.1.6: 会话属性参数表 参数名称 参 数 值 参数说明 默认值 类型 binaryTransfer boolean 指定是否使用二进制格式发送和接收数据 true readOnlyMode String 指定连接设置为只读时的处理行为。” ig- transaction nore” 表示设置 readOnly 无效;” transaction” 表示当 readOnly 为 true 且为非自 动提交时事务为只读事务;”always” 表示当 readOnly 为 true 时,如果为自动提交事务 模式,会话将设置为只读,如果为非自动提 交模式,事务将开始只读。 readOnly boolean 指定连接是否为只读模式 false binaryTransferEnable String 指定逗号分隔的类型列表以启用二进制传 无默认值 输。指定 OID 值或名称。 binaryTransferDisable String 指定逗号分隔的类型列表以禁用二进制传 无默认值 输。指定 OID 值或名称。重写驱动程序缺 省的和 binaryTransferEnable 设置的值 clientEncoding String 指定客户端的编码格式,值为 null 时采用 null jvm 的编码格式 assumeMinServerVersion String 假设服务器至少是这个版本 null ApplicationName String 指定应用程序的名称 Kingbase8 JDBC Driver allowEncodingChanges boolean 指定是否允许更改 clientEncoding false currentSchema String 指定要在搜索路径中设置的模式 null 见续表 13 第3章 JDBC 建立/关闭连接 表 3.1.6 – 续表 参数名称 参 数 值 参数说明 默认值 类型 options String 指定 options 连接初始化参数 null hideUnprivilegedObjects boolean 指定数据库元信息中是否隐藏当前用户没有 false 权限的数据库对象 initParams String 指定用来初始化数据库连接的 sion ses- null 级 参 数, 可 指 定 多 个, 各 个 参 数 之 间 用 分 号 进 行 分 隔, 如 init- Params=client_encoding=’UTF8’; ex- tra_float_digits=2 表 3.1.7: 事务控制参数表 参数名称 参 数 值 参数说明 默认值 指定当一个查询失败时驱动如何做: ” always” 每一个 never 类型 autosave String 查询前都设置 savepoint,失败是都回滚到 savepoint; ”never” 什么都不做; ”conservative” 每一个查询前都设 置 savepoint,但是回滚只针对极少情况才做。 cleanupSavepoints booelan 指定是否清除 autosave 功能在每个语句前设置的保存点 false 表 3.1.8: 通信加密参数表 参数名称 参数值 参数说明 默认值 类型 ssl boolean 指定在使用 JDBC 连接时,是否使用 SSL 安全方式传输数据 false sslmode String 指定控制 SSL 使用的参数 null sslfactory String 指定使用 SSL 的 SSLSocketFactory 类 null sslfactoryarg String 指定被转发到 SSLSocketFactory 类的构造函数的参数 null sslhostnameverifier String 指定一个实现了 javax.net.ssl.HostnameVerifier ,且可以验证服务器的 null 类 见续表 14 第3章 JDBC 建立/关闭连接 表 3.1.8 – 续表 参数名称 参数值 参数说明 默认值 类型 sslcert String 指定客户端 SSL 证书的位置 null sslkey String 指定客户端 PKCS#8 SSL 密钥的位置 null sslrootcert String 指定用于对服务器进行身份验证的根证书的位置 null sslpassword String 指定客户端 ssl 密钥的密码(如果设置了 sslpasswordcallback ,则忽 null 略) sslpasswordcallback String 指定一个实现了 javax.security.auth.callback.CallbackHandler ,且可以 null 为 ssl 密码处理 PasssworCallback 的类 表 3.1.9: 网络控制参数表 参数名称 参 数 值 参数说明 默认值 类型 tcpKeepAlive Boolean 指定是否打开 TCP 的心跳保活机制 false socketTimeout Integer 指定底层 socket receive 的超时时间,单位是秒,值可 0 以为任意正整数,“0”表示没有超时,一直等,直到 返回 loginTimeout Integer 指定等待数据库建立连接的超时时间,单位是秒 0 connectTimeout Integer 指定 Socket 做 connect 时的超时时间,单位是秒 10 cancelSignalTimeout Integer 指定发送取消命令的超时时间,单位是秒 10 socketFactory String 指定用于创建套接字的套接字工厂 null socketFactoryArg String SocketFactory 类的构造函数的参数 null receiveBufferSize Integer 指定 Socket 做 read 时的 buffer 大小,“-1”意思是用 -1 系统默认值 sendBufferSize Integer 指定 Socket 做 send 时的 buffer 大小,“-1”意思是用 -1 系统默认值 15 第3章 JDBC 建立/关闭连接 表 3.1.10: 认证扩展参数表 参数名称 参 数 值 参数说明 默认值 类型 jaasLogin boolean 指定是否在进行 GSSAPI 身份验证之前使用 JAAS 登录 true jaasApplicationName String 指定 JAAS 系统或应用程序登录配置的名称 null kerberosServerName String 指定使用 GSSAPI 进行身份验证时要使用的 Kerberos null 服务名称 useSpnego boolean 指定是否在 SSPI 身份验证请求中使用 SPNEGO false gsslib String 指定强制 SSPI 或 GSSAPI,取值可以为 auto、sspi、 auto gssapi sspiServiceClass 指定用于 SPN 的 Windows SSPI 服务类 String null 表 3.1.11: 高可用扩展参数表 参数名称 参 数 值 参数说明 默认值 指定要连接的服务器类型,取值可以为 any、master、 any 类型 targetServerType String slave、preferSlave loadBalanceHosts boolean 如果禁用,主机按照给定的顺序连接。如果启用,从合 false 适的候选集合中随机选择启用的主机 hostRecheckSeconds Integer 指定检查主机状态的周期,以防它们发生更改,单位是 10 毫秒 replication String 指定启动报文的连接参数 replication 的值 (true, null database)。布尔值 true 告诉后端进入 walsender 模 式,其中可以发出一小组复制命令而不是 SQL 语句。 在 walsender 模式下只能使用简单查询协议。将数据库 作为值传递指示 walsender 连接到 dbname 参数中指定 的数据库,这将允许连接用于从该数据库进行逻辑复制 (后端 >= 8.6) fastFailover boolean 指定是否启动快速故障转移,开启后,如果配置了多主 false 机地址,多次建立连接,后续会默认连接第一次成功连 接的地址,此参数不能与 loadBalanceHosts 参数同时开 启。 16 第3章 JDBC 建立/关闭连接 表 3.1.12: 读写分离配置参数表 参数名称 参 数 值 参数说明 默认值 指定配置文件的路径,只能在连接串中配置,值为 null null 类型 ConfigurePath String 时,不读取配置文件。当连接参数较多时,可通过配置 文件配置连接参数。当文件中配置的连接参数与 URL 中的参数重复时,会覆盖掉 URL 中的参数值 TransactionDispatchStrategy Integer 指定事务中的分发策略,1 表示事务都不分发,2 表示 2 事务中的写语句之前的读语句可以分发。此功能开启需 要同时开启读写分离功能 USEDISPATCH boolean 指定是否使用读写分离功能。此配置项关闭 JDBC 就变 false 成单机 JDBC,无读写分离功能 HOSTLOADRATE Integer 指定主机负载率。此功能开启需要同时开启读写分离功 0 能。根据当前发给主机的语句数目与总语句数目的比例 与 HOSTLOADRATE 设置的比例进行比较,当前者大 于后者时,发给备机,否则发给主机,当总语句数目达 到 Integer.MAX_VALUE 时,用当前分发的实际比例 的分子分母更新当前发给主机的语句数目与总语句数目 SLAVE_ADD String 指定备机地址,可指定多个,用“,”隔开,备机地址支 无 持 IP 地址和域名或者主机名。此功能开启需要同时开 启读写分离功能 SLAVE_PORT String 指定备机端口,与备机地址一一对应,可指定多个,用 无 “,”隔开。此功能开启需要同时开启读写分离功能且设 置备机地址 MASTER_CHECK boolean 指定是否在新建连接时检查当前连接数据库是否为 mas- true ter,如果不是则去 slave 中检查有没有 master,如果还 是找不到就会向上报错。此功能开启需要同时开启读写 分离功能 MONITORINTERVAL Integer 指定集群检测线程每次检测的时间间隔,单位是秒。此 5 功能开启需要同时开启读写分离功能和集群备机检测功 能。 RETRYTIMES Integer 指定失败重发的最高次数。此功能开启需要同时开启读 10 写分离功能 见续表 17 第3章 JDBC 建立/关闭连接 表 3.1.12 – 续表 参数名称 参 数 值 参数说明 默认值 指定失败重发的时间间隔,单位是秒。此功能开启需要 5 类型 RETRYINTERVAL Integer 同时开启读写分离功能 WhiteList String 指定只读函数列表,可指定多个,各个函数之间用分号 null 分隔。目前 WhiteList 只能识别 SQL 语句中函数名后 面带小括号的函数,如果不带,则不能识别。 BlackList String 默认情况下认为函数都是只读的,BlackList 指定写 null 函数列表,可指定多个,各个函数之间用分号分隔, 如:BlackList=updateXXX;writeXXX 这样。目前只支 持函数名字的比较,不支持函数名重载的区分。不与 WhiteList 同时配置,与 WhiteList 同时配置时,只有 BlackList 生效。此功能开启需要同时开启读写分离功 能,目前 BlackList 只能识别 SQL 语句中函数名后面 带小括号的函数,如果不带,则不能识别。 MasterFunctionList String 指定只发主机,但不改变事务状态的函数语句列表, null 可指定多个,各个函数之间用分号分隔,如:MasterFunctionList=updateXXX;writeXXX 这样。目前只支 持函数名字的比较,不支持函数名重载的区分。此功能 开启需要同时开启读写分离功能 TempTable String 指定临时表,如果是查询临时表的查询语句,则只发主 null 机且不改变事务状态。可指定多个,各个表名之间用分 号分隔,如:aaa;bbb 这样。此功能开启需要同时开 启读写分离功能 BlackSqlList String 指定只发主机,但不改变事务状态的 sql 语句列表, null 可 指 定 多 个, 可 指 定 多 个, 各 个 语 句 之 间 用 分 号 分 隔,如:BlackSqlList=SET TRANSACTION READ WRITE;BEGIN READ WRITE 这样。此功能开启需 要同时开启读写分离功能 masterKeyword String 指定一个包含在注释中的单词,包含该注释的语句只发 null 主机,但不改变事务状态 见续表 18 第3章 JDBC 建立/关闭连接 表 3.1.12 – 续表 参数名称 参 数 值 参数说明 默认值 指定各节点的名称,各节点的名称为./ repmgr cluster 无 类型 nodeList String show 命令查询出的 Name 字段。要求开启读写分离 时必须配置此项,不允许为空并要与节点的地址配置 顺序完全一致。各个节点名称之间用逗号分隔,如: nodeList=node1,node2,node3 readListStrategy 指定可分发节点选择列表策略,1 表示所有在线节点均 Integer 1 可分发,2 表示只分发主节点和同步备机节点,3 配 合 differentLsn 使用,表示读语句可分发主机和监测线 程查询到的与主机的 lsn 差异小于 differentLsn 的备 机(监测线程有时间间隔,所以实际上可能会有一些延 迟,数据有可能会发送给与主机的 lsn 差异大于 differentLsn 的备机),4 表示读语句只分发主机和异步备机 节点。此功能开启需要同时开启读写分离功能 differentLsn 指定备机与主机允许的 lsn 差异,默认值为 0,表示备 String 0 机与主机数据同步,由于备机的 lsn 值通常不会大于主 机,所以如果指定为负数,表示不发送备机。该参数在 readListStrategy=3 时生效。 loadBalanceStrategy 备机负载均衡策略,1 表示一个逻辑连接在备机间轮询 Integer 1 进行查询负载,2 表示一个逻辑连接固定在某一备机上 进行查询负载 表 3.1.13: 兼容扩展参数表 参数名称 参 数 值 参数说明 默认值 指定驱动程序如何将 JDBC 转义调用语法转换为底层 call 类型 escapeSyntaxCallMode String SQL,以调用过程或函数。” select” 表示驱动始终使用 select 语句;”callIfNoReturn” 表示如果没有指定返回参 数,则驱动使用 call 语句,否则驱动使用 select 语句; ”call” 表示驱动始终使用 call 语句。 nullConvertEmptyLob boolean 指定当驱动接收到数据库返回的大对象为 null 时,驱动 true 返回给上层空的大对象还是 null,默认返回空大对象 见续表 19 第3章 JDBC 建立/关闭连接 表 3.1.13 – 续表 参数名称 参 数 值 参数说明 默认值 指定数据库存储 SQL 标识符的大小写形式, 取值可以 lower 类型 storeCase String 为 lower、upper 和 original:storeCase 为 lower 时, DatabaseMetaData 的 storesLowerCaseIdentifiers() 返 回 true,storesUpperCaseIdentifiers() 和 storesMixedCaseIdentifiers() 返回 false;storeCase 为 upper 时, storesUpperCaseIdentifiers() 返回 true,其余二者返回 false;storeCase 为 original 时,storesMixedCaseIdentifiers() 返回 true,其余二者返回 false。 structType String 指 定 数 据 库 复 合 类 型 返 回 的 数 据 类 型, 取值可以为 null Struct(即返回 java.sql.Struct)和 KBobject(即返回 com.kingbase8.util.KBobject),为 null 时返回 KBobject。注意:a. 如果返回 Struct 类型,Struct 中包含 字符串类型的字段值,该值两端有双引号且个数不匹配 时,取值会出现错误。b. 如果以 Struct 类型作为绑定 参数,Struct 中包含二进制类型的字段值,该值中包含 转义字符、中文等,无法正确处理(存值时报错,或存 取值不对)。 rowidType String 指定数据库 rowid 类型返回的数据类型, 取值可以为 null rowid(即返回 java.sql.RowId)和 KBobject(即返回 com.kingbase8.util.KBobject),默认值是 null,返回 KBobject。 stringtype 3.1.3 String 指定 bind 参数时设置类型为 unspecified 或者 varchar null 使用 DataSource 连接数据库 连接(Connection)是客户端 Java 应用程序与数据库服务器之间的通信连接,由 KingbaseES JDBC 建 立,在应用程序的代码中使用数据库之前,必须获取一个数据库连接。在 KingbaseES JDBC 中,连接是通过 java.sql.Connection 接口实现。创建一个连接后,可以调用它的方法获得和设置连接、管理事务和创建语句对象等。 DataSource 接口是在 JDBC 3.0 的规范中定义的另外一种获取数据源连接的方法。使用 DataSource 进行数 据库连接可以提高应用程序的可移植性,因为应用程序使用一个逻辑名称建立与数据库的连接,该逻辑名通过使用 JNDI(Java Naming and Directory Interface) 命名服务映射到真正的 DataSource 对象,该 DataSource 对象表示了一 个真正的数据库连接。如果数据源的信息发生变化,只需修改该 DataSource 对象的属性,而不需要修改应用程序。 DataSource 对象是推荐使用的方法,它使得应用程序更容易移植和维护,而且应用程序可以透明地使用连接池 和分布事务的功能。J2EE 组件多通过 DataSource 对象与数据源建立连接的。 20 第3章 JDBC 建立/关闭连接 DataSource 接口的实现可以提供连接池的功能,也可以不提供。在基本的 DataSource 接口的实现中,客户的连 接对象与物理的数据库连接是一对一的关系,当连接对象关闭的时候,物理的数据库连接也要关闭,因此,每个客户 连接都要打开、初始化和关闭一次物理的数据库连接,这显然降低系统的性能。连接池则维护了一组物理的数据库连 接,在客户间重用来提高性能和可扩展性。 当连接串的属性中包括 (’/’, ’&’, ’?’, ’%’) 等特殊字符时,DataSource 可以提供另外一种解决方法(请参考使用 DriverManager 连接数据库 一节)。用户可以通过以下提供的 setXXX 方法在 DataSource 初始化时设置连接属性。 此时不必对连接串中的特殊字符进行转义。 KingbaseES JDBC 在 KBSimpleDataSource 类中实现了 DataSource 接口,在 Jdbc3PoolingDataSource 类中实 现了具有连接池功能的 DataSource 接口。下面分别介绍它们的使用方式。 • 使用 DataSource 连接数据库(不使用 JNDI) • 使用 DataSource 连接数据库(使用 JNDI) • 连接池 3.1.3.1 使用 DataSource 连接数据库(不使用 JNDI) 通过 DataSource 来建立连接的过程主要分为以下几个步骤: a. 创建 KBSimpleDataSource 创建一个 KingbaseES 的 DataSource,要执行以下语句: KBSimpleDataSource ds = new KBSimpleDataSource(); b. 初始化连接属性 标准的 DataSource 属性包括:databaseName,password,portNumber,serverName,user。 用户通过以下方法来对这些属性进行设置: setDatabaseName(String dbname); setPassword(String pwd); setPortNumber(int pn); setServerName(String sn); setUser(String user); 这里的赋值实际上是指定了建立一个物理连接所需要的属性。 例 3-2. 获得一个 Connection 实例 用户在应用程序中可以通过如下方法来获得一个 Connection 实例: Connection conn=ds.getConnection("user","pwd"); 21 第3章 JDBC 建立/关闭连接 Connection conn=ds.getConnection(); 3.1.3.2 使用 DataSource 连接数据库(使用 JNDI) JNDI(Java Naming and directory Interface),Java 名字目录接口,是 J2EE 提供的名字服务(J2SE 中需要获 取额外的类包才可实现同样功能)。JNDI 机制由一个通用的客户机接口和一组 JNDI 提供者组成,提供者用于定义 后台名字系统。 KingbaseES JDBC 驱动程序提供通过 JNDI 查找方式来获取数据源的方法,其步骤如下: a. 建立数据源 例 3-3. 建立数据源 KBSimpleDataSource ds = new KBSimpleDataSource(); ds.setDatabaseName("test") ; ds.setUser("system") ; ds.setPassword("manager") ; ds.setPortNumber(54321) ; Context ctx = null; try { Hashtable env = new Hashtable (5); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put (Context.PROVIDER_URL, "file:/job/jndi"); ctx = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } ctx.rebind("DataSource", ds); 特别说明:此段程序运行,需要从 http://java.sun.com 下载两个 jar 文件,其名字分别为:fscontext.jar 和 providerutil.jar(这两个类包文件在同一个压缩文件中,目前最新的名字为 fscontext-1_2-beta3.zip,以后其名 可能会发生变化)。 b. 通过 JNDI 查找来获取数据源 22 第3章 JDBC 建立/关闭连接 例 3-4. 通过 JNDI 查找来获取数据源 Context ctx2 = null; try { Hashtable env = new Hashtable (5); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put (Context.PROVIDER_URL, "file:/job/jndi"); ctx2 = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } DataSource ds2 = (DataSource)ctx2.lookup("DataSource"); c. 使用数据源做 SQL 语句处理 例 3-5. 使用数据源做 SQL 语句处理 Connection conn = ds2.getConnection(); Statement stmt = conn.createStatement() ; String sql = "select * from tu9"; ResultSet rs = stmt.executeQuery( sql ) ; while ( rs.next() ) { System.out.print(rs.getString("name") + rs.getString("nick")) ; } System.out.println(); rs.close() ; stmt.close() ; conn.close(); import java.sql.*; import javax.sql.*; import javax.naming.*; import java.util.*; import com.kingbase8.ds.*; public class example1 { 23 第3章 JDBC 建立/关闭连接 public static void main(String [] args) { try { KBSimpleDataSource ds = new KBSimpleDataSource(); ds.setDatabaseName("test") ; ds.setUser("system") ; ds.setPassword("manager") ; ds.setPortNumber(54321) ; /* 建立 JNDI 的环境 Context ctx = null; try { Hashtable env = new Hashtable (5); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put (Context.PROVIDER_URL, "file:/job/jndi"); ctx = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } ctx.rebind("DataSource", ds); Context ctx2 = null; try { Hashtable env = new Hashtable (5); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put (Context.PROVIDER_URL, "file:/job/jndi"); ctx2 = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } DataSource ds2 = (DataSource)ctx2.lookup("DataSource"); try { Connection conn = ds2.getConnection(); Statement stmt = conn.createStatement() ; stmt.executeUpdate( 24 第3章 JDBC 建立/关闭连接 "create table dataSource (id int)"); stmt.executeUpdate( "insert into dataSource values (1)"); ResultSet rs = stmt.executeQuery( "select * from dataSource"); while(rs.next()) { System.out.println("id:"+ rs.getInt(1)); } stmt.executeUpdate("drop table dataSource"); rs.close(); stmt.close(); conn.close(); } catch(SQLException e) { e.printStackTrace() ; } } catch(Exception e) { e.printStackTrace() ; } } } 3.1.3.3 连接池 Jdbc3PoolingDataSource 类是实现了 DataSource 接口的数据库连接池的管理类。 使用 Jdbc3PoolingDataSource 类可以提高程序的运行效率。建立数据库连接将耗费大量的资源,而把连接放到 池中,可以节省大量的建立新连接的开销。 使用方法如下: a. 创建 Jdbc3PoolingDataSource 对象。 Jdbc3PoolingDataSource ds = new Jdbc3PoolingDataSource(); b. 设置相应属性。 ds.setDataSourceName("A Data Source"); ds.setDatabaseName("test") ; ds.setUser("system") ; 25 第3章 JDBC 建立/关闭连接 ds.setPassword("manager") ; ds.setMaxConnections(10) ; ds.setInitialConnections(10) ; ds.setPortNumber(54321) ; c. 获取连接。 Connection conn = ds.getConnection() ; d. 查建立 SQL 语句,执行相应的操作。 Statement stmt = conn.createStatement() ; String sql = "select * from tu9"; ResultSet rs = stmt.executeQuery( sql ) ; while ( rs.next() ) { System.out.print(rs.getString("name")+ rs.getString("nick")) ; } System.out.println(); rs.close() ; stmt.close() ; e. 关闭连接。 conn.close(); f. 关闭池。 ds.close(); 说明:池建立一次即可,最好放在系统初始化时执行;在系统退出时,再执行关闭池的操作。 例如: 例 3-6. 连接池的使用 import java.sql.*; import javax.sql.*; import java.util.*; import com.kingbase8.jdbc3.*; import com.kingbase8.*; public class example2 { public static void main(String [] args) throws Exception { 26 第3章 JDBC 建立/关闭连接 Jdbc3PoolingDataSource ds = new Jdbc3PoolingDataSource(); ds.setDataSourceName("A Data Source") ; ds.setDatabaseName("test") ; ds.setUser("system") ; ds.setPassword("manager") ; ds.setMaxConnections(10) ; ds.setInitialConnections(10) ; ds.setPortNumber(54321) ; Connection conn = ds.getConnection() ; Statement stmt = conn.createStatement() ; stmt.executeUpdate("create table pool (id int)"); stmt.executeUpdate("insert into pool values (1)"); ResultSet rs = stmt.executeQuery("select * from pool"); while(rs.next()) { System.out.println("id:"+ rs.getInt(1)); } stmt.executeUpdate("drop table pool"); rs.close(); stmt.close(); conn.close(); ds.close(); } } 使用具有连接池功能的连接方法也可以通过 JDNI 方式建立数据库连接,方法与使用 DataSource 连接数据库 (使用 JNDI) 中的方法相同。 3.2 关闭与数据库的连接 要关闭与数据库的连接,只需要对连接对象 conn 调用 close() 方法: conn.close(); 3.3 JDBC Driver API a. public Connection connect(String url, Properties info) 功能: 试图创建一个到给定 URL 的数据库连接。如果驱动程序识别出它是连接到给定 URL 的错误类型的驱动程序, 那么它应该返回”null”。 27 第3章 JDBC 建立/关闭连接 参数: url - 要连接到的数据库的 URL; info - 做为连接参数的任意字符串标记/值对的列表。通常至少应该包括”user” 和”password” 属性。 返回值: 表示到 URL 的连接的 Connection 对象。 b. public boolean acceptsURL(String url) 功能: 查询驱动程序是否认为它可以打开到给定 URL 的连接。 参数: url - 数据库的 URL。 返回值: 如果此驱动程序理解给定的 URL,则返回 true;否则,返回 false。 c. public DriverPropertyInfo[] getPropertyInfo(String url,Properties info) 功能: 获得此驱动程序的可能属性信息。 参数: url - 要连接到的数据库的 URL; info - 将要在打开的连接上发送的标记/值对的建议列表。 返回值: 描述可能属性的 DriverPropertyInfo 对象的数组。如果不需要任何属性,该数组可能是一个空数组。 d. public int getMajorVersion() 功能: 获取此驱动程序的主版本号。 返回值: 此驱动程序的主版本号。 e. public int getMinorVersion() 功能: 获得此驱动程序的次版本号。 返回值: 此驱动程序的次版本号。 28 第3章 JDBC 建立/关闭连接 f. public boolean jdbcCompliant() 功能: 报告此驱动程序是否是一个真正的 JDBC CompliantTM 驱动程序。 返回值: 如果此驱动程序是 JDBC 兼容的,则返回 true;否则,返回 false。 3.4 JDBC Connection API 1. public Statement createStatement() 功能: 创建一个 Statement 对象来将 SQL 语句发送到数据库。不带参数的 SQL 语句通常使用 Statement 对象执行。 如果多次执行相同的 SQL 语句,使用 PreparedStatement 对象可能更有效。 返回值: 一个新的默认 Statement 对象。 2. public PreparedStatement prepareStatement(String sql) 功能: 创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。带有 IN 参数或不带有 IN 参数的 SQL 语句都可以被预编译并存储在 PreparedStatement 对象中。然后可以有效地使用此对象来多次执行该语句。 参数: sql - 可能包含一个或多个’?’ IN 参数占位符的 SQL 语句。 返回值: 包含预编译 SQL 语句的新的默认 PreparedStatement 对象。 3. public CallableStatement prepareCall(String sql) 功能: 创建一个 CallableStatement 对象来调用数据库存储过程。CallableStatement 对象提供了设置其 IN 和 OUT 参 数的方法,以及用来执行调用存储过程的方法。 参数: sql - 可以包含一个或多个’?’ 参数占位符的 SQL 语句。通常此语句是使用 JDBC 调用转义语法指定的。 返回值: 包含预编译 SQL 语句的新的默认 CallableStatement 对象。 29 第3章 JDBC 建立/关闭连接 4. public void setAutoCommit(boolean autoCommit) 功能: 将此连接的自动提交模式设置为给定状态。如果连接处于自动提交模式下,则它的所有 SQL 语句将被执行并作 为单个事务提交。否则,它的 SQL 语句将聚集到事务中,直到调用 commit 方法或 rollback 方法为止。默认情 况下,新连接处于自动提交模式。 参数: autoCommit - 为 true 表示启用自动提交模式;为 false 表示禁用自动提交模式。 5. public boolean getAutoCommit() 功能: 获取此 Connection 对象的当前自动提交模式。 返回值: 此 Connection 对象的自动提交模式的当前状态。 6. public void commit() 功能: 使所有上一次提交/回滚后进行的更改成为持久更改,并释放此 Connection 对象当前持有的所有数据库锁。此 方法只应该在已禁用自动提交模式时使用。 7. public void rollback() 功能: 取消在当前事务中进行的所有更改,并释放此 Connection 对象当前持有的所有数据库锁。此方法只应该在已禁 用自动提交模式时使用。 8. public void close() 功能: 立即释放此 Connection 对象的数据库和 JDBC 资源,而不是等待它们被自动释放。 9. public boolean isClosed() 功能: 查询此 Connection 对象是否已经被关闭。如果在连接上调用了 close 方法或者发生某些严重的错误,则连接被 关闭。只有在调用了 Connection.close 方法之后被调用时,此方法才保证返回 true。 返回值: 如果此 Connection 对象是关闭的,则返回 true;如果它仍然处于打开状态,则返回 false。 10. public DatabaseMetaData getMetaData() 功能: 30 第3章 JDBC 建立/关闭连接 获取一个 DatabaseMetaData 对象,该对象包含关于此 Connection 对象所连接的数据库的元数据。元数据包括 关于数据库的表、受支持的 SQL 语法、存储过程、此连接功能等等的信息。 返回值: 此 Connection 对象的一个 DatabaseMetaData 对象。 11. public void setReadOnly(boolean readOnly) 功能: 将此连接设置为只读模式,作为驱动程序启用数据库优化的提示。 参数: readOnly - 为 true 表示启用只读模式;为 false 表示禁用只读模式。 12. public boolean isReadOnly() 功能: 查询此 Connection 对象是否处于只读模式。 返回值: 如果此 Connection 对象是只读的,则返回 true;否则返回 false。 13. public String getCatalog() 功能: 获取此 Connection 对象的当前目录名称。 返回值: 当前目录名称;如果不存在,则返回 null。 14. public void setTransactionIsolation(int level) 功能: 试图将此 Connection 对象的事务隔离级别更改为给定的级别。可能的事务隔离级别是 Connection 接口中定义 的常量。 参数: level - 以下 Connection 常量之一: Connection.TRANSACTION_READ_UNCOMMITTED Connection.TRANSACTION_READ_COMMITTED Connection.TRANSACTION_REPEATABLE_READ Connection.TRANSACTION_SERIALIZABLE (注意,不能使用 Connection.TRANSACTION_NONE,因为它指定了不受支持的事务。) 31 第3章 JDBC 建立/关闭连接 15. public int getTransactionIsolation() 功能: 获取此 Connection 对象的当前事务隔离级别。 返回值: 当前事务隔离级别,它将是以下常量之一: Connection.TRANSACTION_READ_UNCOMMITTED Connection.TRANSACTION_READ_COMMITTED Connection.TRANSACTION_REPEATABLE_READ Connection.TRANSACTION_SERIALIZABLE Connection.TRANSACTION_NONE。 16. public SQLWarning getWarnings() 功能: 获取此 Connection 对象上的调用报告的第一个警告。如果有多个警告,则后续警告将被链接到第一个警告,可 以通过对之前获得的警告调用 SQLWarning.getNextWarning 方法获取。 返回值: 第一个 SQLWarning 对象;如果不存在,则返回 null。 17. public void clearWarnings() 功能: 清除为此 Connection 对象报告的所有警告。调用此方法后,在为此 Connection 对象报告新的警告前,getWarnings 方法将返回 null。 18. public Statement createStatement(int resultSetType,int resultSetConcurrency) 功能: 创建一个 Statement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。此方法与上述 createStatement 方法相同,但它允许重写默认结果集类型和并发性。已创建结果集的可保存性可调用 getHoldability() 确 定。 参数: resultSetType - 结果集类型,它是 ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE 之一。 resultSetConcurrency - 并发类型,它是 32 第3章 JDBC 建立/关闭连接 ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE 之一。 返回值: 一个新的 Statement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。 19. public PreparedStatement prepareStatement(String sql,int resultSetType,int resultSetConcurrency) 功能: 创建一个 PreparedStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。此方法与上述 prepareStatement 方法相同,但它允许重写默认结果集类型和并发性。已创建结果集的可保存性可调用 getHoldability() 确定。 参数: sql - 一个 String 对象,它是将被发送到数据库的 SQL 语句,可以包含一个或多个’?’ IN 参数; resultSetType - 结果集类型,它是 ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE 之一。 resultSetConcurrency - 并发类型,它是 ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE 之一。 返回值: 包含预编译的 SQL 语句的新 PreparedStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对 象。 20. public CallableStatement prepareCall(String sql,int resultSetType,int resultSetConcurrency) 功能: 创建一个 CallableStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。此方法与上述 prepareCall 方法相同,但它允许重写默认结果集类型和并发性。已创建结果集的可保存性可调用 getHoldability() 确定。 参数: sql - 一个 String 对象,它是将被发送给数据库的 SQL 语句,可以包含一个或多个’?’ 参数; resultSetType - 结果集类型,它是 33 第3章 JDBC 建立/关闭连接 ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE 之一。 resultSetConcurrency - 并发类型,它是 ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE 之一。 返回值: 一个包含预编译的 SQL 语句的新 CallableStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。 21. public void setHoldability(int holdability) 功能: 将使用此 Connection 对象创建的 ResultSet 对象的默认可保存性 (holdability) 更改为给定可保存性。ResultSet 对象的默认可保存性可调用 DatabaseMetaData.getResultSetHoldability() 确定。 参数: holdability - ResultSet 的可保存性常量,它是 ResultSet.HOLD_CURSORS_OVER_COMMIT ResultSet.CLOSE_CURSORS_AT_COMMIT 之一。 22. public int getHoldability() 功能: 获取使用此 Connection 对象创建的 ResultSet 对象的当前可保存性。 返回值: 可 保 存 性, 它 是 ResultSet.HOLD_CURSORS_OVER_COMMIT 或 Result- Set.CLOSE_CURSORS_AT_COMMIT 之一。 23. public Savepoint setSavepoint() 功能: 在当前事务中创建一个未命名的保存点 (savepoint),并返回表示它的新 Savepoint 对象。 返回值: 新的 Savepoint 对象。 34 第3章 JDBC 建立/关闭连接 24. public Savepoint setSavepoint(String name) 功能: 在当前事务中创建一个具有给定名称的保存点,并返回表示它的新 Savepoint 对象。 参数: name - 包含保存点名称的 String。 返回值: 新的 Savepoint 对象。 25. public void rollback(Savepoint savepoint) 功能: 取消所有设置给定 Savepoint 对象之后进行的更改。 参数: savepoint - 要回滚到的 Savepoint 对象。 26. public void releaseSavepoint(Savepoint savepoint) 功能: 从当前事务中移除指定的 Savepoint 和后续 Savepoint 对象。在已移除保存点之后,对该保存点的任何引用都会 导致抛出 SQLException。 参数: savepoint - 要移除的 Savepoint 对象。 27. public Statement createStatement(int resultSetType,int resultSetConcurrency,int resultSetHoldability) 功能: 创建一个 Statement 对象,该对象将生成具有给定类型、并发性和可保存性的 ResultSet 对象。此方法与上述 createStatement 方法相同,但它允许重写默认结果集类型、并发性和可保存性。 参数: resultSetType - 以下 ResultSet 常量之一: ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE resultSetConcurrency - 以下 ResultSet 常量之一: ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE resultSetHoldability - 以下 ResultSet 常量之一: 35 第3章 JDBC 建立/关闭连接 ResultSet.HOLD_CURSORS_OVER_COMMIT ResultSet.CLOSE_CURSORS_AT_COMMIT 返回值: 一个新的 Statement 对象,该对象将生成具有给定类型、并发性和可保存性的 ResultSet 对象。 28. public PreparedStatement prepareStatement(String sql,int resultSetType,int resultSetConcurrency,int resultSetHoldability) 功能: 创建一个 PreparedStatement 对象,该对象将生成具有给定类型、并发性和可保存性的 ResultSet 对象。 参数: sql - 一个 String 对象,它是将被发送到数据库的 SQL 语句,可以包含一个或多个’?’ IN 参数; resultSetType - 以下 ResultSet 常量之一: ResultSet.TYPE_FORWARD_ONLY ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE resultSetConcurrency - 以下 ResultSet 常量之一: ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE resultSetHoldability - 以下 ResultSet 常量之一: ResultSet.HOLD_CURSORS_OVER_COMMIT ResultSet.CLOSE_CURSORS_AT_COMMIT 返回值: 一个包含预编译 SQL 语句的新 PreparedStatement 对象,该对象将生成具有给定类型、并发性和可保存性的 ResultSet 对象。 29. public CallableStatement prepareCall(String sql,int resultSetType,int resultSetConcurrency,int resultSetHoldability) 功能: 创建一个 CallableStatement 对象,该对象将生成具有给定类型和并发性的 ResultSet 对象。此方法与上述 prepareCall 方法相同,但它允许重写默认结果集类型、结果集并发性类型和可保存性。 参数: sql - 一个 String 对象,它是将被发送到数据库的 SQL 语句,可以包含一个或多个’?’ 参数; resultSetType - 以下 ResultSet 常量之一: ResultSet.TYPE_FORWARD_ONLY 36 第3章 JDBC 建立/关闭连接 ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.TYPE_SCROLL_SENSITIVE resultSetConcurrency - 以下 ResultSet 常量之一: ResultSet.CONCUR_READ_ONLY ResultSet.CONCUR_UPDATABLE resultSetHoldability - 以下 ResultSet 常量之一: ResultSet.HOLD_CURSORS_OVER_COMMIT ResultSet.CLOSE_CURSORS_AT_COMMIT 返回值: 一个包含预编译 SQL 语句的新 CallableStatement 对象,该对象将生成具有给定类型、并发性和可保存性的 ResultSet 对象。 30. public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) 功能: 创建一个默认 PreparedStatement 对象,该对象能获取自动生成的键。给定常量告知驱动程序是否可以获取自 动生成的键。如果 SQL 语句不是一条 INSERT 语句,或者 SQL 语句能够返回自动生成的键(这类语句的列表 是特定于供应商的),则忽略此参数。 参数: sql - 可能包含一个或多个’?’ IN 参数占位符的 SQL 语句; autoGeneratedKeys - 指 示 是 否 应 该 返 回 自 动 生 成 的 键 的 标 志, 它 是 State- ment.RETURN_GENERATED_KEYS 或 Statement.NO_GENERATED_KEYS 之一。 返回值: 一个包含预编译 SQL 语句的新 PreparedStatement 对象,该对象能够返回自动生成的键。 31. public PreparedStatement prepareStatement(String sql,int[] columnIndexes) 功能: 创建一个能返回由给定数组指定的自动生成键的默认 PreparedStatement 对象。此数组包含目标表中列的索 引,而目标表包含应该可返回的自动生成的键。如果 SQL 语句不是 INSERT 语句,或者 SQL 语言能够返回 自动生成的键(这类语句的列表是特定于供应商的),则驱动程序将忽略该数组。 参数: sql - 可能包含一个或多个’?’ IN 参数占位符的 SQL 语句; columnIndexes - 列索引数组,这些索引指示应该从一个或多个插入行中返回的那些列。 返回值: 一个包含预编译语句的新 PreparedStatement 对象,该对象能够返回由给定列索引数组指定的自动生成键。 37 第3章 JDBC 建立/关闭连接 32. public PreparedStatement prepareStatement(String sql,String[] columnNames) 功能: 创建一个能返回由给定数组指定的自动生成键的默认 PreparedStatement 对象。此数组包含目标表中列的名 称,而目标表包含应该返回的自动生成键。如果 SQL 语句不是 INSERT 语句,或者 SQL 语言能够返回自动 生成的键(这类语句的列表是特定于供应商的),则驱动程序将忽略该数组。 参数: sql - 可能包含一个或多个’?’ IN 参数占位符的 SQL 语句; columnNames - 列名称数组,这些名称指示应该从一个或多个插入行中返回的那些列。 返回值: 一个包含预编译语句的新 PreparedStatement 对象,该对象能够返回由给定列名称数组指定的自动生成键。 33. public Clob createClob() 功能: 构造实现 Clob 接口的对象。返回的对象最初不包含任何数据。Clob 接口的 setAsciiStream、setCharacterStream 和 setString 方法可用来向 Clob 添加数据。在 PG 兼容模式下,该接口未实现。 返回值: 实现 Clob 接口的对象。 34. public Blob createBlob() 功能: 构造实现 Blob 接口的对象。返回的对象最初不包含任何数据。Blob 接口的 setBinaryStream 和 setBytes 方法 可用来向 Blob 添加数据。在 PG 兼容模式下,该接口未实现。 返回值: 实现 Blob 接口的对象。 35. public SQLXML createSQLXML() 功能: 构造实现 SQLXML 接口的对象。返回的对象最初不包含任何数据。SQLXML 接口的 createXmlStreamWriter 和 setString 方法可用来向 SQLXML 对象添加数据。 返回值: 实现 SQLXML 接口的对象。 3.5 JDBC DataSource API a. public XAConnection getXAConnection() 38 第3章 JDBC 建立/关闭连接 功能: 尝试建立可在分布式事务中使用的物理数据库连接。 返回值: 可在分布式事务中使用的 XAConnection 对象,该对象表示到数据源的物理连接。 b. public XAConnection getXAConnection(String user, String password) 功能: 使用给定的用户名和密码,尝试建立一个物理数据库连接。返回的连接可在分布式事务中使用。 参数: user - 为其建立连接的数据库用户; password - 用户的密码。 返回值: 可在分布式事务中使用的 XAConnection 对象,该对象表示到数据源的物理连接。 3.6 JDBC ConnectionPoolDataSource API a. public PooledConnection getPooledConnection() 功能: 尝试建立可用作入池连接的物理数据库连接。 返回值: PooledConnection 对象,该对象是到此 ConnectionPoolDataSource 对象表示的数据库的物理连接。 b. public PooledConnection getPooledConnection(String user, String password) 功能: 尝试建立可用作入池连接的物理数据库连接。 参数: user - 为其建立连接的数据库用户; password - 用户的密码。 返回值: PooledConnection 对象,该对象是到此 ConnectionPoolDataSource 对象表示的数据库的物理连接。 39 第3章 JDBC 建立/关闭连接 3.7 JDBC PooledConnection API a. public Connection getConnection() 功能: 创建并返回一个 Connection 对象,它是此 PooledConnection 对象表示的物理连接的句柄。 返回值: 一个 Connection 对象,它是到此 PooledConnection 对象的句柄。 b. public void close() 功能: 关闭此 PooledConnection 对象表示的物理连接。 c. public void addConnectionEventListener(ConnectionEventListener listener) 功能: 注册给定的事件侦听器,以便在此 PooledConnection 对象上发生事件时它将得到通知。 参数: listener - 一个组件(通常为连接池管理器),它实现了 ConnectionEventListener 接口,并在关闭连接或发生错 误时应得到通知。 d. public void removeConnectionEventListener(ConnectionEventListener listener) 功能: 从在此 PooledConnection 对象上发生事件时得到通知的组件所组成的列表中移除给定的事件侦听器。 参数: listener - 一个组件(通常为连接池管理器),它实现了 ConnectionEventListener 接口,并已作为侦听器向此 PooledConnection 对象注册。 e. public void addStatementEventListener(StatementEventListener listener) 功能: 向此 PooledConnection 对象注册一个 StatementEventListener。该连接创建的 PreparedStatement 关闭或检测 为无效时希望获得通知的组件可以使用此方法向此 PooledConnection 对象注册一个 StatementEventListener。 参数: listener - 实现将向此 PooledConnection 对象注册的 StatementEventListener 接口的组件。 f. public void removeStatementEventListener(StatementEventListener listener) 功能: 从一个组件列表中移除指定的 StatementEventListener,该列表由驱动程序检测到 PreparedStatement 已关闭 或无效时将获得通知的组件组成。 40 第3章 JDBC 建立/关闭连接 参数: listener - 实现以前向此 PooledConnection 对象注册的 StatementEventListener 接口的组件。 3.8 JDBC XAConnection API a. public XAResource getXAResource() 功能: 获取 XAResource 对象,事务管理器将使用该对象管理此 XAConnection 对象如何参与到分布式事务中。 返回值: XAResource 对象。 b. public PooledConnection getPooledConnection(String user, String password) 功能: 尝试建立可用作入池连接的物理数据库连接。 参数: user - 为其建立连接的数据库用户; password - 用户的密码。 返回值: PooledConnection 对象,该对象是到此 ConnectionPoolDataSource 对象表示的数据库的物理连接。 3.9 JDBC XADataSource API a. public XAConnection getXAConnection() 功能: 尝试建立可在分布式事务中使用的物理数据库连接。 返回值: 可在分布式事务中使用的 XAConnection 对象,该对象表示到数据源的物理连接。 b. public XAConnection getXAConnection(String user, String password) 功能: 尝使用给定的用户名和密码,尝试建立一个物理数据库连接。返回的连接可在分布式事务中使用。 参数: 41 第3章 JDBC 建立/关闭连接 user - 为其建立连接的数据库用户; password - 用户的密码。 返回值: 可在分布式事务中使用的 XAConnection 对象,该对象表示到数据源的物理连接。 42 第 4 章 JDBC 创建语句对象 4 第 章 JDBC 创建语句对象 连接一旦建立,就可向数据库传送 SQL 语句,而且对可被发送的 SQL 语句类型不加任何限制,它允许使用特定 的数据库语句。 KingbaseES JDBC 提供了三个类,用于向数据库发送 SQL 语句,Connection 接口中的三个方法可用于创建这 些类的实例: a. Statement 对象:由方法 createStatement 所创建,用于发送简单的 SQL 语句。 b. PreparedStatement 对象:由方法 prepareStatement 所创建,用于发送带有一个或多个输入参数(IN 参数)的 SQL 语句。 c. CallableStatement 对象:由方法 prepareCall 所创建,用于执行 SQL 存储过程。 • Statement 对象 • PreparedStatement 对象 • CallableStatement 对象 • JDBC Statement API • JDBC PreparedStatement API • JDBC CallableStatement API 4.1 Statement 对象 Statement 对象由方法 createStatement 所创建,Statement 对象用于发送简单的 SQL 语句,来进行查询或对数 据库进行更新,Statement 对象提供三种方法执行 SQL 语句: a. execute 方法用于执行返回多个结果集或更新多个元组的 SQL 语句; b. executeQuery 方法用于执行返回单个结果集的 SQL 语句; c. executeUpdate 方法用于执行含有 INSERT、UPDATE 或 DELETE 语句或者不返回任何内容的 SQL 语句,如 DDL 语句。 例 4-1. Statement 对象的使用 43 第 4 章 JDBC 创建语句对象 Connection conn = DriverManager.getConnection(url, "system", "manager"); Statement stmt=conn.createStatement(); stmt.executeUpdate("update table1 set col1=1"); • 支持 SQL 语句的批处理功能。Statement 和它的子类通过 addBatch() 方法支持批处理功能。 • 支持 getGeneratedKeys() 方法: 1. 当使用方法 executeUpdate(String sql,int autoGeneratedKeys)、execute(String sql,int autoGeneratedKeys) 时,调用 getGeneratedKeys(),返回只由 OID 一列构成的结果集。 2. 当使用方法 executeUpdate(String sql,int[] keyColumnIndexes)、executeUpdate(String sql, String[] keyColumnNames)、execute(String sql,int[] keyColumnIndexes), execute(String sql, String[] keyColumnNames) 时,调用 getGeneratedKeys(),返回由指定列构成的结果集(默认不包含 OID)。 例 4-2. executeUpdate(String sql,int autoGeneratedKeys) 示例 Connection conn = DriverManager.getConnection(url, "system", "manager"); Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO ORDERS (ISBN, CUSTOMERID) " + "VALUES(195123018, 'BILLING')", Statement.RETURN_GENERATED_KEYS); System.out.println("rows:" + rows); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if(b == true) { System.out.println(rs.getString(1)); } 例 4-3. execute(String sql,int autoGeneratedKeys) 示例 Connection conn = DriverManager.getConnection(url, "system", "manager"); Statement stmt = conn.createStatement(); boolean result = stmt.execute("INSERT INTO ORDERS (ISBN, CUSTOMERID) " + "VALUES(195123018, 'BILLING')", Statement.RETURN_GENERATED_KEYS); System.out.println("result:" + result); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if(b == true) { System.out.println(rs.getString(1)); } 44 第 4 章 JDBC 创建语句对象 例 4-4 executeUpdate(String sql, String[] keyColumnNames) 示例 String keyColumn[] = {"ORDER_ID"}; Connection conn = DriverManager.getConnection(url, "system", "manager"); Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO ORDERS (ISBN, CUSTOMERID) " + "VALUES(195123020, 'BILLING')", keyColumn); System.out.println("rows:" + rows); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if(b == true) { System.out.println(rs.getString(1)); } 例 4-5. execute(String sql, String[] keyColumnNames) 示例 String keyColumn[] = {"ORDER_ID"}; Connection conn = DriverManager.getConnection(url, "system", "manager"); Statement stmt = conn.createStatement(); boolean result = stmt.execute("INSERT INTO ORDERS (ISBN, CUSTOMERID) " + "VALUES (195123020, 'BILLING')", keyColumn); System.out.println("result:" + result); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if (b == true) { System.out.println(rs.getString(1)); } 例 4-6 通过 addBatch() 方法实现批处理 Statement stmt = conn.createStatement(); Employee[] employees = new Employee[2]; employees[0] = new Employee(); employees[1] = new Employee(); employees[0].salary = 100; employees[0].id = 1; employees[1].salary = 200; employees[1].id = 2; 45 第 4 章 JDBC 创建语句对象 int[] rows; for(int i=0; i T getObject(int columnIndex, Class type) throws SQLException 131 第 6 章 ROWID 接口 检索此 ResultSet 对象的当前行中指定列的值,如果转换支持,将转换为 SQL 类型的列到所请求的 Java 数据 类型。如果转换不受支持,或者为该类型指定为 null,则抛出 SQLException 。 参数类型: T - 由此 Class 对象建模的类的类型 参数: columnIndex - 第一列是 1,第二列是 2,... type - 表示将指定列转换为的 Java 数据类型的类。 结果: 一个持有列值的 type 的实例。 异常: SQLException - 如果不支持转换,则 type 为 null 或发生其他错误。异常的 getCause()方法可能会 提供更详细的异常,例如,如果发生转换错误。 SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法。 从以下版本开始: 1.7 3. RowId getRowId(int columnIndex) throws SQLException 以 Java 编程语言中 java.sql.RowId 对象的形式获取此 ResultSet 对象的当前行中指定列的值。 参数: columnIndex - 第一个列是 1,第二个列是 2,…… 返回: 列值,如果该值为 SQL NULL,则返回值为 null 。 抛出: SQLException - 如果 columnIndex 无效;如果发生数据库访问错误或在已关闭的结果集上调用此方 法。 SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法。 4. void updateRowId(int columnIndex, RowId x) throws SQLException 用 RowId 值更新指定列。更新方法用于更新当前行或插入行中的列值。更新方法不更新底层数据库;更新数据 库要调用 updateRow 或 insertRow 方法。 参数: columnIndex - 第一个列是 1,第二个列是 2,…… x - 列值 抛出: 132 第 6 章 ROWID 接口 SQLException - 如果 columnIndex 无效;如果发生数据库访问错误;结果集并发性为 CONCUR_READ_ONLY 或在已关闭的结果集上调用此方法。 SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法。 CallableStatement 的接口: 1. RowId getRowId(int parameterIndex) throws SQLException 以 java.sql.RowId 对象的形式获取指定 JDBC ROWID 参数的值。 参数: parameterIndex - 第一个参数是 1,第二个参数是 2,…… 返回: 表示被用作指定参数的 JDBC ROWID 值的 RowId 对象。如果该参数包含一个 SQL NULL,则返回 null 值。 抛出: SQLException - 如果 parameterIndex 无效;如果发生数据库访问错误,或者在关闭的 CallableStatement 上调用此方法。 SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法。 133 第 7 章 JDBC 大对象数据处理 7 第 章 JDBC 大对象数据处理 在 KingbaseES 中,大对象数据用于保存那些无法在通常 SQL 表里面保存的数据,例如声音、图象、大文本等。 在 KingbaseES 兼容 oracle 版本中提供了用来存储大对象数据的数据类型 BLOB 和 CLOB,用来存储大数据量的二 进制数据和字符数据。在兼容 PG 的版本中,大对象统一存储在一张系统表中,用户表中只存储大对象实际存储的地 址,类型为 oid。 KingbaseES JDBC 中提供了两个接口用于处理大对象数据:java.sql.Blob 和 java.sql.Clob。oracle 兼容模式下数 据库提供了两种类型来存储数据,接口提供的两个类分别对应处理这两种数据类型,故两个类的接口均已实现。但在 PG 兼容模式下数据库对大对象统一存储,且驱动的 Clob 的类只实现了部分获取数据的接口,设置数据的接口均未 实现,故 Clob 接口只能进行数据的接收,如果要更新大对象数据只能使用 Blob 的接口。Clob 接口在两种兼容情况 下的具体实现情况可参照JDBC Clob API 。 • 大对象数据的读取 • 大对象数据的更新 • JDBC Blob API • JDBC Clob API • JDBC SQLXML API 7.1 大对象数据的读取 同检索其他数据类型一样,用同样的方法可以从一个结果集中检索 Blob 和 Clob 这两种数据类型的数据,该获 得方法为: Blob blob = rs.getBlob(); Clob clob = rs.getClob(); 与其它数据类型不同,调用 getBlob() 和 getClob() 之后,需要使用 Blob 和 Clob 接口的方法访问数据。 oracle 兼容模式下: 用下面脚本创建包含 Clob 字段的表: 134 第 7 章 JDBC 大对象数据处理 CREATE TABLE clob_table(col1 Clob, col2 Clob, col3 Clob); 用下面脚本创建包含 Blob 字段的表: CREATE TABLE blob_table(col1 Blob, col2 Blob, col3 Blob); PG 兼容模式下: 用下面脚本创建包含 Clob 字段的表: CREATE TABLE clob_table(col1 oid, col2 oid, col3 oid); 用下面脚本创建包含 Blob 字段的表: CREATE TABLE blob_table(col1 oid, col2 oid, col3 oid); 例 7-1. Clob 查询示例 这个例子展示了如何查询 Clob 字段 处理 Clob 的 java 程序段: String sql_select = "select * from clob_table"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(sql_select); int count = 1; while (resultSet.next()) { System.out.println(" 第" + count + " 条记录"); Clob clob1 = resultSet.getClob(1); Clob clob2 = resultSet.getClob(2); Clob clob3 = resultSet.getClob(3); System.out.println("clob1:" + clob1.getSubString(1, (int) clob1.length())); System.out.println("clob2:" + clob2.getSubString(1, (int) clob2.length())); System.out.println("clob3:" + clob3.getSubString(1, (int) clob3.length())); count++; } resultSet.close(); count = 1; resultSet = statement.executeQuery(sql_select); 135 第 7 章 JDBC 大对象数据处理 while (resultSet.next()) { System.out.println(" 第" + count + " 条记录"); for (int i = 0; i < 3; i++) { Clob clob = resultSet.getClob(i + 1); Reader reader = clob.getCharacterStream(); StringWriter sWriter = new StringWriter(); int j = -1; while ((j = reader.read()) != -1) { sWriter.write(j); } String finalClob = new String(sWriter.getBuffer()); System.out.println(finalClob); } count++; } resultSet.close(); 例 7-2. Blob 查询示例 这个例子展示了如何查询 Blob 字段 处理 Blob 的 java 程序段: String sql_select = "select * from blob_table"; statement = connection.createStatement(); resultSet = statement.executeQuery(sql_select); int count = 1; while (resultSet.next()) { System.out.println(" 第" + count + " 条记录"); Blob blob1 = resultSet.getBlob(1); Blob blob2 = resultSet.getBlob(1); Blob blob3 = resultSet.getBlob(1); System.out.println("blob1: " + new String(blob1.getBytes(1, (int) blob1.length()))); System.out.println("blob2: " + new String(blob2.getBytes(1, (int) blob2.length()))); 136 第 7 章 JDBC 大对象数据处理 System.out.println("blob3: " + new String(blob3.getBytes(1, (int) blob3.length()))); count++; } resultSet.close(); count = 1; resultSet = statement.executeQuery(sql_select); while (resultSet.next()) { System.out.println(" 第" + count + " 条记录"); for (int i = 0; i < 3; i++) { Blob blob = resultSet.getBlob(i + 1); 使用 getBinaryStream 方法获得 blob 列的数据。 */ /* String finalblob = new String(sWriter.getBuffer()); System.out.println(finalblob); } count++; } resultSet.close(); 7.2 大对象数据的更新 在 PreparedStatement 类中,可以使用 setBlob() 和 setClob() 方法把 Blob 和 Clob 对象当成参数传递给 SQL 语 句。例如:authorImage 和 authorBio 是通过其它 SQL 语句检索出来的 Blob 和 Clob 对象: PreparedStatement pstmt = conn.prepareStatement( "insert into bio(image,text) values(?,?)"); pstmt.setBlob(1,authorImage); pstmt.setClob(2,authorBio); pstmt.executeUpdate(); 137 第 7 章 JDBC 大对象数据处理 完整的示例请参见下文。 此外,在 oracle 兼容模式下,通过 PrepareStatement 对象的 setBinaryStream、setBytes 和 setObject 可以设置 语句中的 Blob 类型的参数; 使用 setCharacterStream、setString、setAsciiStream 和 setObject 方法可以设置 Clob 类 型的参数。 请看下面完整的示例。例 7-3、7-4、7-5 只能在 oracle 兼容模式下执行, 例 7-6 在 PG 和 oracle 兼容模式下均可 执行。 用下面脚本创建包含 Clob 字段的表: CREATE TABLE clob_table(col1 Clob, col2 Clob, col3 Clob); 用下面脚本创建包含 Blob 字段的表: CREATE TABLE blob_table(col1 Blob, col2 Blob, col3 Blob); 例 7-3. Clob 插入示例 这个例子展示了如何向 Clob 列插入数据 处理 Clob 的 java 程序段: /* * 插入 Clob 数据 */ String sql_insert = "insert into clob_table values(?,?,?)"; File file = new File("e:/test.xml"); Reader read1, read2, read3; read1 = new FileReader(file); read2 = new FileReader(file); read3 = new FileReader(file); preparedStatement = connection.prepareStatement(sql_insert); preparedStatement.setCharacterStream(1, read1); preparedStatement.setCharacterStream(2, read2); preparedStatement.setCharacterStream(3, read3); preparedStatement.execute(); String str = "Welcome to Kingbase!"; preparedStatement = connection.prepareStatement(sql_insert); preparedStatement.setString(1, str); preparedStatement.setString(2, str); 138 第 7 章 JDBC 大对象数据处理 preparedStatement.setString(3, str); preparedStatement.execute(); 例 7-4. Blob 插入示例 这个例子展示了如何向 Blob 列插入数据 处理 Blob 的 java 程序段: /* * 插入 Blob 数据 */ String sql_insert = "insert into blob_table values(?,?,?)"; File file = new File("e:/test.xml"); InputStream input1, input2, input3; input1 = new FileInputStream(file); input2 = new FileInputStream(file); input3 = new FileInputStream(file); preparedStatement = connection.prepareStatement(sql_insert); preparedStatement.setBinaryStream(1, input1); preparedStatement.setBinaryStream(2, input2); preparedStatement.setBinaryStream(3, input3); preparedStatement.execute(); String str = "Welcome to Kingbase!"; preparedStatement = connection.prepareStatement(sql_insert); preparedStatement.setBytes(1, str.getBytes()); preparedStatement.setBytes(2, str.getBytes()); preparedStatement.setBytes(3, str.getBytes()); preparedStatement.execute(); 例 7-5. Clob 更新示例 这个例子展示了如何使用 Clob 的 setCharacterStream、setAsciiStream 和 setString 方法更新 Clob 字段 处理 Clob 的 java 程序段: /* * 使用 Clob 的 setAsciiStream、setCharacterStream 和 SetString 方法更新 * Clob 列。 */ String query = "Select * from clob_table for update"; Statement statement = connection.createStatement(); 139 第 7 章 JDBC 大对象数据处理 ResultSet resultSet = statement.executeQuery(query); if (resultSet.next()) { Clob clob = resultSet.getClob(1); /* * 使用 setAsciiStream 方法更新 Clob 列,其中 clob.length() + 1 表示在 * 原值后追加新的值, * 原值为 “Welcome to Kingbase!”,更新后的值为 “Welcome to Kingbase! * Test has sucessful!”。 */ OutputStream os = clob.setAsciiStream(clob.length() + 1); String temp = "Test has sucessful!"; byte[] tempByte = temp.getBytes(); os.write(tempByte); os.close(); /* * 使用 setCharacterStream 方法更新 Clob 列,其中 clob.length() + 1 * 表示在原值后追加新的值, * 原值为 “Welcome to Kingbase!”,更新后的值为 “Welcome to Kingbase! * Welcome to Kingbase!”。 */ clob = resultSet.getClob(2); Writer writer = clob.setCharacterStream(clob.length() + 1); temp = "Welcome to Kingbase!"; writer.write(temp); writer.close(); /* * 使用 setString 方法更新 Clob 列,其中 temp.length() 表示原值的更新 * 位置,如果原值的长度 * 大于或者等于 temp.length() 的值,则新值代替对应位置的原值; 否则原值 * 长度小于 temp.length() 的 * 值,更新时会报错。原值为 “Welcome to Kingbase!”,更新后的值为 * “Welcome to Kingbase!Hello, Kingbase!”。 */ clob = resultSet.getClob(3); temp = "Hello, Kingbase!"; clob.setString(clob.length() + 1, temp); } 例 7-6. Blob 更新示例 这个例子展示了如何使用 Blob 的 setBinaryStream 和 setBytes 方法更新 Blob 字段 140 第 7 章 JDBC 大对象数据处理 处理 Blob 的 java 程序段: /* * 使用 Blob 的 setBinaryStream 和 setString 方法更新 blob 列。 */ String query = "Select * from blob_table for update"; Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(query); if (resultSet.next()) { Blob blob = resultSet.getBlob(1); /* * 使用 setBinaryStream 方法更新 blob 列,其中 blob.length() + 1 表示 * 在原值后追加新的值。 * 原值为 “Welcome to Kingbase!”,更新后的值为 “Welcome to Kingbase! * Welcome to Kingbase!”。 */ OutputStream output = blob.setBinaryStream(blob.length() + 1); String temp = "Welcome to Kingbase!"; output.write(temp.getBytes()); output.close(); /* * 使用 setBytes 方法更新 blob 列,其中 blob.length() + 1 表示原值的 * 更新位置,如果原值的长度大于或者等于 blob.length() + 1 的值,则新值 * 代替对应位置的原值; 否则原值长度小于 blob.length() + 1 * 的值,更新时会报错。原值为 “Welcome to Kingbase!”,更新后的值为 * “Welcome to Kingbase!Hello, Kingbase!”。 */ blob = resultSet.getBlob(2); temp = "Hello, Kingbase!"; blob.setBytes(blob.length() + 1, temp.getBytes()); } 7.3 JDBC Blob API a. public long length() 功能: 返回此 Blob 对象指定的 BLOB 值中的字节数。 返回值: 141 第 7 章 JDBC 大对象数据处理 BLOB 的字节长度。 b. public byte[] getBytes(long pos,int length) 功能: 以 byte 数组的形式获取此 Blob 对象表示的全部或部分 BLOB 值。此 byte 数组包含从位置 pos 开始的 length 个连续字节。 参数: pos - 要提取的 BLOB 值中第一个字节的顺序位置;第一个字节位于位置 1 处。 length - 要复制的连续字节的数量;length 的值必须大于等于 0。 返回值: 一个字节数组,它包含此 Blob 对象指定的 BLOB 值中的 length 个连续字节(从位置 pos 处的字节开始。 c. public InputStream getBinaryStream() 功能: 以流的形式获取此 Blob 实例指定的 BLOB 值。 返回值: 包含 BLOB 数据的流。 d. public long position(byte[] pattern,long start) 功能: 获取此 Blob 对象表示的 BLOB 值中指定 byte 数组 pattern 开始处的字节位置。对 pattern 的搜索从位置 start 开始。 参数: pattern - 要搜索的字节数组。 start - 开始搜索的位置;第一个位置是 1。 返回值: pattern 出现的位置,否则返回 -1。 e. public long position(Blob pattern,long start) 功能: 获取此 Blob 对象指定的 BLOB 值中 pattern 开始处的字节位置。从位置 start 开始搜索。 参数: pattern - 指定要搜索的 BLOB 值的 Blob 对象。 start - BLOB 值中开始进行搜索的位置;第一个位置是 1。 返回值: 142 第 7 章 JDBC 大对象数据处理 pattern 开始处的位置,否则返回 -1。 f. public int setBytes(long pos,byte[] bytes) 功能: 从位置 pos 处开始,将给定 byte 数组写入此 Blob 对象表示的 BLOB 值,并返回写入的字节数。该 byte 数组 将从位置 pos 开始重写 Blob 对象中的现有字节。如果在写 byte 数组时到达 Blob 值的末尾,则将增加 Blob 值 的长度,以容纳额外的字节。 参数: pos - BLOB 对象开始进行写入操作的位置;第一个位置是 1。 bytes - 要写入此 Blob 对象表示的 BLOB 值中的 byte 数组。 返回值: 写入的字节数。 g. public int setBytes(long pos,byte[] bytes,int offset,int len) 功能: 将所有或部分给定的 byte 数组写入此 Blob 对象表示的 BLOB 值中,并返回写入的字节数。写入操作从 BLOB 值中的位置 pos 处开始;写入给定 byte 数组中的 len 个字节。该 byte 数组将从位置 pos 开始重写 Blob 对象 中的现有字节。如果在写 byte 数组时到达 Blob 值的末尾,则将增加 Blob 值的长度,以容纳额外的字节。 参数: pos - BLOB 对象开始进行写入操作的位置;第一个位置是 1。 bytes - 要写入此 BLOB 对象中的 byte 数组。 offset - 数组 bytes 中的偏移量,从此处开始读取要设置的字节。 len - 要从 byte 数组 bytes 中写入 BLOB 值的字节数。 返回值: 写入的字节数。 h. public OutputStream setBinaryStream(long pos) 功能: 获取用于写入此 Blob 对象表示的 BLOB 值的流。该流从位置 pos 处开始。写入流中的字节将从位置 pos 开始 重写 Blob 对象中的现有字节。如果在写入流时到达 Blob 值的末尾,则将增加 Blob 值的长度,以容纳额外的 字节。 参数: pos - BLOB 值中开始进行写入操作的位置;第一个位置是 1 。 返回值: 可以将数据写入其中的 java.io.OutputStream 对象。 143 第 7 章 JDBC 大对象数据处理 i. public void truncate(long len) 功能: 截取此 Blob 对象表示的 BLOB 值,使其长度为 len 个字节。 参数: len - 此 Blob 对象表示的 BLOB 值将被截取的字节长度。 j. public void free() 功能: 此方法释放 Blob 对象以及它所占用的资源。调用 free 方法后,该对象将无效。 k. public InputStream getBinaryStream(long pos,long length) 功能: 返回包含部分 Blob 值的 InputStream 对象,该值从 pos 指定的字节开始,长度为 length 个字节。 参数: pos - 将获取的部分值第一个字节的偏移量。Blob 中的第一个字节在位置 1 处。 length - 将获取的部分值的字节长度。 返回值: 将从中读取部分 Blob 值的 InputStream。 7.4 JDBC Clob API a. public long length() 功能: 获取此 Clob 对象指定的 CLOB 值中的字符数。 返回值: CLOB 的字符长度。 b. public String getSubString(long pos,int length) 功能: 获取此 Clob 对象指定的 CLOB 值中指定子字符串的副本。子字符串开始于位置 pos 处,有 length 个连续字 符。 参数: pos - 要提取的子字符串的第一个字符。第一个字符位于位置 1 处。 length - 要复制的连续字符的数量;length 的值必须大于等于 0 。 144 第 7 章 JDBC 大对象数据处理 返回值: 一个 String,它是由此 Clob 对象指定的 CLOB 值中的指定子字符串 c. public Reader getCharacterStream() 功能: 以 java.io.Reader 对象形式(或字符流形式)获取此 Clob 对象指定的 CLOB 值。 返回值: 包含 CLOB 数据的 java.io.Reader 对象。 d. public InputStream getAsciiStream() 功能: 以 ascii 流形式获取此 Clob 对象指定的 CLOB 值。 返回值: 包含 CLOB 数据的 java.io.InputStream 对象。 e. public long position(String searchstr,long start) 功能: 获取此 Clob 对象表示的 SQL CLOB 值中指定子字符串 searchstr 出现的字符位置。从位置 start 开始搜索。 PG 兼容模式下未实现。 参数: searchstr - 要搜索的子字符串。 start - 开始搜索的位置;第一个位置是 1。 返回值: 子字符串出现的位置;如果没有出现,则返回 -1;第一个位置是 1。 f. public long position(Clob searchstr,long start) 功能: 获取此 Clob 对象中指定的 Clob 对象 searchstr 出现的字符位置。从位置 start 开始搜索。PG 兼容模式下未实 现。 参数: searchstr - 要搜索的 Clob 对象。 start - 开始搜索的位置;第一个位置是 1。 返回值: Clob 对象出现的位置;如果没有出现,则返回 -1;第一个位置是 1。 145 第 7 章 JDBC 大对象数据处理 g. public int setString(long pos,String str) 功能: 在位置 pos 处将给定 Java String 写入此 Clob 对象指定的 CLOB 值中。该字符串将从位置 pos 开始重写 Clob 对象中的现有字节。如果在写入给定字符串时到达 Clob 值的末尾,则将增加 Clob 值的长度,以容纳额外的字 符。PG 兼容模式下未实现。 参数: pos - 开始写入此 Clob 对象表示的 CLOB 值的位置;第一个位置是 1。 str - 要写入此 Clob 指定的 CLOB 值中的字符串。 返回值: 写入的字符数。 h. public int setString(long pos,String str,int offset,int len) 功能: 将 str 的 len 个字符(从字符 offset 开始)写入此 Clob 表示的 CLOB 值中。该字符串将从位置 pos 开始重写 Clob 对象中的现有字节。如果在写入给定字符串时到达 Clob 值的末尾,则将增加 Clob 值的长度,以容纳额外 的字符。PG 兼容模式下未实现。 参数: pos - 开始写入此 CLOB 对象的位置;第一个位置是 1。 str - 要写入此 Clob 对象表示的 CLOB 值中的字符串。 offset - str 中开始读取要写入字符的偏移量。 len - 要写入的字符数。 返回值: 写入的字符数。 i. public OutputStream setAsciiStream(long pos) 功能: 获取用于将 Ascii 字符写入此 Clob 对象表示的 Clob 值中的流,从位置 pos 处开始。写入流中的字符将从位置 pos 开始重写 Clob 对象中的现有字节。如果在将字符写入流中时到达 Clob 值的末尾,则将增加 Clob 值的长 度,以容纳额外的字符。PG 兼容模式下未实现。 参数: pos - 开始写入此 CLOB 对象中的位置;第一个位置是 1。 返回值: 可以将 ASCII 编码字符写入其中的流。 146 第 7 章 JDBC 大对象数据处理 j. public Writer setCharacterStream(long pos) 功能: 获取用于将 Unicode 字符流写入此 Clob 对象表示的 CLOB 值中(位置 pos 处)的流。写入流中的字符将从位 置 pos 开始重写 Clob 对象中的现有字节。如果在将字符写入流中时到达 Clob 值的末尾,则将增加 Clob 值的 长度,以容纳额外的字符。PG 兼容模式下未实现。 参数: pos - 开始写入 CLOB 值中的位置;第一个位置是 1。 返回值: 可将 Unicode 编码字符写入其中的流。 k. public void truncate(long len) 功能: 截取此 Clob 指定的 CLOB 值,使其长度为 len 个字符。 参数: len - CLOB 值应被截取的字符长度。 l. public void free() 功能: 此方法释放 Clob 对象以及它所占用的资源。调用 free 方法后,该对象无效。 7.5 JDBC SQLXML API a. public void free() 功能: 此方法关闭此对象并释放其持有的资源。 b. public InputStream getBinaryStream() 功能: 以流的形式获取此 SQLXML 实例指定的 XML 值。 返回值: 包含 XML 数据的流。 c. public OutputStream setBinaryStream() 功能: 获取可用于写入此 SQLXML 实例表示的 XML 值的流。 147 第 7 章 JDBC 大对象数据处理 返回值: 可以写入数据的流。 d. public Reader getCharacterStream() 功能: 以 java.io.Reader 对象的形式获取此 SQLXML 实例指定的 XML 值。 返回值: 包含 XML 数据的流。 e. public Writer setCharacterStream() 功能: 获取用于写入此 SQLXML 实例表示的 XML 值的流。 返回值: 可以写入数据的流。 f. public String getString() 功能: 返回此 SQLXML 实例指定的 XML 值的字符串表示形式。 返回值: 此 SQLXML 实例指定的 XML 值的字符串表示形式。 g. public void setString(String value) 功能: 将此 SQLXML 实例指定的 XML 值设置为给定的 String 表示形式。 参数: value - XML 值。 h. public T getSource(Class sourceClass) 功能: 返回读取此 SQLXML 实例指定的 XML 值的 Source。Source 用作对 XML 解析器和 XSLT 转换器的输入。 参数: sourceClass - 源的类,或为 null。如果该类为 null,则将返回特定于供应商的 Source 实现。至少支持以下类 javax.xml.transform.dom.DOMSource - 返回 DOMSource javax.xml.transform.sax.SAXSource - 返回 SAXSource javax.xml.transform.stax.StAXSource - 返回 StAXSource javax.xml.transform.stream.StreamSource - 返回 StreamSource 148 第 7 章 JDBC 大对象数据处理 返回值: 读取 XML 值的 Source。 i. public T setResult(Class resultClass) 功能: 返回设置此 SQLXML 实例指定的 XML 值的 Result。 参数: resultClass - 所得的类,或为 null。如果 resultClass 为 null,则将返回特定于供应商的 Result 实现。至少支持 以下类: javax.xml.transform.dom.DOMResult - 返回 DOMResult javax.xml.transform.sax.SAXResult - 返回 SAXResult javax.xml.transform.stax.StAXResult - 返回 StAXResult javax.xml.transform.stream.StreamResult - 返回 StreamResult 返回值: 返回设置 XML 值的 Result。 149 第 8 章 JDBC 事务处理 8 第 章 JDBC 事务处理 • 事务的提交与回滚 • JDBC 事务的隔离级别 • JDBC Savepoint API 8.1 事务的提交与回滚 应用程序创建一个连接时,该连接默认事务自动提交,用户可以在 Connection 对象中设置事务提交模式(分为 自动提交和非自动提交两种),方法如下: Connection.setAutoCommit(boolean autoCommit); 当 autoCommit 为 true 时,表示为自动提交模式,这种情况下,该连接下的所有语句在执行完之后都会自动提 交。 在非自动提交模式下,用户在一个事务执行完成之后需要显式调用 Connection.commit 方法来提交事务。方法如 下: conn.commit(); 否则,当该事务需要回滚时,则需要显式调用 Connection.rollback 方法。 conn.rollback(); 为了对事务进行更细级别上的控制,JDBC 3.0 增加了 Savepoint 接口,它代表一个逻辑事务点,在设置为非自 动提交模式下,可以设置多个 Savepoint,在回滚的时候可以回滚到指定的 Savepoint,但从事务开始到 Savepoint 之 间的操作仍保留。将事务回滚到 Savepoint 时,在该 Savepoint 之后所作的全部更改都将被撤消。下面的例子说明了 Savepoint 的使用方法。 例 8-1. Savepoint 的使用方法 过程描述:向表中插入一条记录,设置 savepoint svpt1,插入第二条记录,回滚事务到 svpt1,当提交事务后, 第二条记录被取消,第一条被插入。 150 第 8 章 JDBC 事务处理 Connection connection = DriverManager.getConnection(url, "system", "manager"); connection.setAutoCommit(false); Statement stmt = connection.createStatement(); int row1 = stmt.executeUpdate( "INSERT INTO transaction (number) VALUES(1)"); Savepoint svpt1 = connection.setSavepoint("SAVEPOINT_1"); int row2 = stmt.executeUpdate( "INSERT INTO transaction (number) VALUES(2)"); connection.rollback(svpt1); connection.commit(); 对于未命名 Savepoint 对象,可以通过 getSavepointId() 获取此 Savepoint 对象表示的保存点的 ID。 对于命名 Savepoint 对象,可以通过 getSavepointName() 获取此 Savepoint 对象表示的保存点的名称。 8.2 JDBC 事务的隔离级别 KingbaseES 的 JDBC 驱 动 支 持 四 种 事 务 隔 离 级 别:TRANSACTION_READ_COMMITTED TRANSACTION_READ_UNCOMMITTED 、TRANSACTION_REPEATABLE_READ 和 、 TRANSAC- TION_SERIALIZABLE,默认的事务隔离级别为 TRANSACTION_READ_COMMITTED。 • TRANSACTION_READ_UNCOMMITTED: 读未提交,如果一个事务已经开始写数据,则另一个事务不允许同时进行写操作,但允许其它事务读 此行数据。该隔离级别避免了更新丢失,但可能出现脏读,也就是事务 B 读取到事务 A 未提交的数 据。 • TRANSACTION_READ_COMMITTED: 读已提交,如果是一个读事务,则允许其它事务读写,如果是写事务,则会禁止其它事务访问该行数 据。该隔离级别避免了脏读,但可能出现不可重复读。事务 A 事先读取了数据,然后事务 B 更新了 数据并提交了事务,而事务 A 再次读取该数据时,数据已经发生了改变。 • TRANSACTION_REPEATABLE_READ: 可重复读,在一个事务内,多次读取同一个数据,在这个事务还没结束时,其它事务不能访问该数 据,这样在同一个事务内两次读到的数据是一样的。读事务将会禁止其它写事务,但允许其它读事 务;写事务则禁止了其它任何事务,包括读写,这样避免了不可重复读和脏读, • TRANSACTION_SERIALIZABLE 151 第 8 章 JDBC 事务处理 可序列化,提供严格的事务隔离,要求事务序列化执行。事务只能一个接一个地执行,不能并发执 行。这是最高的事务隔离级别,但是性能是最低的。在该级别下,事务的顺序执行可以避免脏读、不 可重复读和幻读。 用户可以通过 Connection.setTransactionIsolation 来 指 定 事 务 隔 离 级 别, 通 过 Connec- tion.getTransactionIsolation 来读取当前事务隔离级别。 注意: 目前,在 KingbaseES 数据库中设置 TRANSACTION_READ_UNCOMMITTED 隔离级别时,实际生效 的是 TRANSACTION_READ_COMMITTED 隔离级别。具体的事务隔离级别描述请参见《KingbaseES 数据库概 念》手册中的” 事务的隔离级别” 章节。 例 8-2. 事务隔离级别设置和获取 Connection connection = DriverManager.getConnection(url, "system", "manager"); connection.setTransactionIsolation( Connection.TRANSACTION_READ_UNCOMMITTED); connection.getTransactionIsolation(); 8.3 JDBC Savepoint API a. public int getSavepointId() 功能: 获取此 Savepoint 对象表示的保存点的生成 ID。 返回值: 此保存点的数字 ID。 b. public String getSavepointName() 功能: 获取此 Savepoint 对象表示的保存点的名称。 返回值: 此保存点的名称。 152 第9章 9 第 章 JDBC 元数据处理 JDBC 元数据处理 • 数据库元数据 • 参数元数据 • 结果集元数据 • 数据类型映射表 • JDBC Databasemetadata API • JDBC ParameterMetaData API • JDBC ResultSetMetaData API 9.1 数据库元数据 KingbaseES JDBC 的 Databasemetadata 接口可以向用户提供有关数据库的一些元信息,用户在建立了到数据 库的一个连接之后,就可以获得该数据库的元数据信息。 例如:conn.getMetaData(); 例 9-1. 获得数据库元数据 Connection connection = DriverManager.getConnection(url, "system", "manager"); DatabaseMetaData metadata = connection.getMetaData(); Connection connection = metadata.getConnection(); int DatabaseMajorVersion = metadata.getDatabaseMajorVersion(); 153 第9章 JDBC 元数据处理 int JDBCMajorVersion = metadata.getJDBCMajorVersion(); String[] types = {"TABLE"}; ResultSet rs = getTables(null, null, "%", types); while(rs.next()){ String tableName = rs.getString("TABLE_NAME"); String tableType = rs.getString("TABLE_TYPE"); String remarks = rs.getString("REMARKS"); System.out.println(tableName + " - " + tableType + " - " + remarks); } 9.2 参数元数据 KingbaseES JDBC 的 ParameterMetaData 接口可用于获取关于 PreparedStatement 对象中每个参数标记的类型 和属性信息的对象。对于某些查询和驱动程序实现,由 ParameterMetaData 对象返回的数据在 PreparedStatement 执行前可能不可用。 例如:pstmt.getParameterMetaData(); 例 9-2. 获取参数元数据 Connection connection = DriverManager.getConnection(url, "system", "manager"); PreparedStatement pstmt = connection.prepareStatement( "insert into test values (?, ?, ?)"); ParameterMetaData pmetaData = pstmt.getParameterMetaData(); int parameterCount = pmetaData.getParameterCount(); boolean signed = pmetaData.isSigned(1); ... 154 第9章 9.3 JDBC 元数据处理 结果集元数据 KingbaseES JDBC 的 ResultSetMetaData 接口可用于获取关于 ResultSet 对象中列的类型和属性信息的对象。 例如:rs.getMetaData(); 除标准接口外,还有私有接口可以判断列是否为隐含列。 例如:((KbResultSetMetaData) rmetaData).isColumnInvisible(1); 注意: 结果集默认不会返回隐含列,即执行 select * from xxx 时,不会返回隐含列的内容,需要显示指定查询列。 例 9-3. 获得结果集元数据 Connection connection = DriverManager.getConnection(url, "system", "manager"); Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("select t1,t2 from test;"); ResultSetMetaData rmetaData = rs.getMetaData(); int columnCount = rmetaData.getColumnCount(); boolean caseSensitive = rmetaData.isCaseSensitive(1); boolean columnInvisible = ((KbResultSetMetaData) rmetaData).isColumnInvisible(1); ... 9.4 数据类型映射表 KingbaseES 在存入数据库时,经过数据类型映射,转换成相应的数据类型进行存储。因此在获取数据时,数据 库返回的 OID 与创建的 OID 不同。具体映射关系请参见下表: 155 第9章 JDBC 元数据处理 数据库类型 KESTypeOid JDBC SQL 类型 Java 类型 int2 21 Types.SAMLLINT java.lang.Integer int4 23 Types.INTEGER java.lang.Integer oid 26 Types.BIGINT java.lang.Long int8 20 Types.BIGINT java.lang.Long money 790 Types.DOUBLE java.lang.Double numeric 1700 Types.NUMERIC java.math.BigDecimal float4 700 Types.REAL java.lang.Float float8 701 Types.DOUBLE java.lang.Double char 18 Types.CHAR java.lang.String bpchar 1042 Types.CHAR java.lang.String varchar 1043 Types.VARCHAR java.lang.String text 25 Types.VARCHAR java.lang.String name 19 Types.VARCHAR java.lang.String bytea 17 Types.BINARY [B (byte[])] bool 16 Types.BIT java.lang.Boolean bit 1560 Types.BIT java.lang.Boolean date 1082 Types.DATE java.sql.Date time 1083 Types.TIME java.sql.Time timetz 1266 Types.TIME java.sql.Time timestamp 1114 Types.TIMESTAMP java.sql.Timestamp timestamptz 1184 Types.TIMESTAMP java.sql.Timestamp refcursor 1790 Types.REF_CURSOR java.sql.ResultSet json 114 Types.OTHER com.kingbase8.util.KBobject point 600 Types.OTHER com.kingbase8.geometric.KBpoint uuid 2950 Types.OTHER java.util.UUID 见续表 156 第9章 JDBC 元数据处理 表 9.4.1 – 续表 数据库类型 KESTypeOid JDBC SQL 类型 Java 类型 yminterval 7002 Types.OTHER com.kingbase8.jdbc.YMInterval dsinterval 7000 Types.OTHER com.kingbase8.jdbc.DSInterval 9.5 JDBC Databasemetadata API 1. public boolean allProceduresAreCallable() 功能: 获取当前用户是否可以调用 getProcedures 方法返回的所有过程。 返回值: 如果是这样,则返回 true;否则返回 false 。 2. public boolean allTablesAreSelectable() 功能: 获取当前用户是否可以使用 SELECT 语句中的 getTables 方法返回的所有表。 返回值: 如果是这样,则返回 true;否则返回 false 。 3. public String getURL() 功能: 获取此 DBMS 的 URL。 返回值: 此 DBMS 的 URL,如果无法生成该 URL,则返回 null 。 4. public String getUserName() 功能: 获取此数据库的已知的用户名称。 返回值: 数据库用户名称。 5. public boolean isReadOnly() 功能: 获取此数据库是否处于只读模式。 157 第9章 JDBC 元数据处理 返回值: 如果是这样,则返回 true;否则返回 false 。 6. public boolean nullsAreSortedHigh() 功能: 获取 NULL 值是否被高排序。高排序是指在域中,NULL 值的排序高于其他任何值。在升序中,如果此方法返 回 true,则 NULL 值将出现在末尾。相反,nullsAreSortedAtEnd 方法指示 NULL 值始终存储在末尾,不管排 序顺序如何。 返回值: 如果是这样,则返回 true;否则返回 false 。 7. public boolean nullsAreSortedLow() 功能: 获取 NULL 值是否被低排序。低排序是指在域中,NULL 值的排序低于其他任何值。在升序中,如果此方法返 回 true,则 NULL 值将出现在开头。相反,nullsAreSortedAtStart 方法指示 NULL 值始终存储在开头,不管 排序顺序如何。 返回值: 如果是这样,则返回 true;否则返回 false 。 8. public boolean nullsAreSortedAtStart() 功能: 获取 NULL 值是否始终排在开头,不管排序顺序如何。 返回值: 如果是这样,则返回 true;否则返回 false 。 9. public boolean nullsAreSortedAtEnd() 功能: 获取 NULL 值是否始终排在末尾,不管排序顺序如何。 返回值: 如果是这样,则返回 true;否则返回 false 。 10. public String getDatabaseProductName() 功能: 获取此数据库产品的名称。 返回值: 数据库产品名称。 158 第9章 JDBC 元数据处理 11. public String getDatabaseProductVersion() 功能: 获取此数据库产品的版本号。 返回值: 数据库版本号。 12. public String getDriverName() 功能: 获取此 JDBC 驱动程序的名称。 返回值: JDBC 驱动程序名称。 13. public String getDriverVersion() 功能: 获取此 JDBC 驱动程序的 String 形式的版本号。 返回值: JDBC 驱动程序版本。 14. public int getDriverMajorVersion() 功能: 获取此 JDBC 驱动程序的主版本号。 返回值: JDBC 驱动程序的主版本。 15. public int getDriverMinorVersion() 功能: 获取此 JDBC 驱动程序的次版本号。 返回值: JDBC 驱动程序的次版本号。 16. public boolean usesLocalFiles() 功能: 获取此数据库是否将表存储在本地文件中。 返回值: 如果是这样,则返回 true;否则返回 false 。 159 第9章 JDBC 元数据处理 17. public boolean usesLocalFilePerTable() 功能: 获取此数据库是否为每个表使用一个文件。 返回值: 如果此数据库为每个表使用一个本地文件,则返回 true;否则返回 false 。 18. public boolean supportsMixedCaseIdentifiers() 功能: 获取此数据库是否将大小写混写的不带引号的 SQL 标识符作为区分大小写的形式处理,并且最后以大小写混合 形式存储它们。 返回值: 如果是这样,则返回 true;否则返回 false 。 19. public boolean storesUpperCaseIdentifiers() 功能: 获取此数据库是否将大小写混写的不带引号的 SQL 标识符作为不区分大小写的形式处理,并以大写形式存储它 们。 返回值: 如果是这样,则返回 true;否则返回 false 。 20. public boolean storesLowerCaseIdentifiers() 功能: 获取此数据库是否将大小写混写的不带引号的 SQL 标识符作为不区分大小写的形式处理,并以小写形式存储它 们。 返回值: 如果是这样,则返回 true;否则返回 false 。 21. public boolean storesMixedCaseIdentifiers() 功能: 获取此数据库是否将大小写混写的不带引号的 SQL 标识符作为不区分大小写的形式处理,并以大小写混合形式 存储它们。 返回值: 如果是这样,则返回 true;否则返回 false 。 22. public boolean supportsMixedCaseQuotedIdentifiers() 功能: 160 第9章 JDBC 元数据处理 获取此数据库是否将大小写混写的带引号的 SQL 标识符作为区分大小写的形式处理,并且最后以大小写混合形 式存储它们。 返回值: 如果是这样,则返回 true;否则返回 false 。 23. public boolean storesUpperCaseQuotedIdentifiers() 功能: 获取此数据库是否将大小写混写的带引号的 SQL 标识符作为不区分大小写的形式处理,并以大写形式存储它 们。 返回值: 如果是这样,则返回 true;否则返回 false 。 24. public boolean storesLowerCaseQuotedIdentifiers() 功能: 获取此数据库是否将大小写混写的带引号的 SQL 标识符作为不区分大小写的形式处理,并以小写形式存储它 们。 返回值: 如果是这样,则返回 true;否则返回 false 。 25. public boolean storesMixedCaseQuotedIdentifiers() 功能: 获取此数据库是否将大小写混写的带引号的 SQL 标识符作为不区分大小写的形式处理,并以大小写混合形式存 储它们。 返回值: 如果是这样,则返回 true;否则返回 false 。 26. public String getIdentifierQuoteString() 功能: 获取用于引用 SQL 标识符的字符串。如果标识符引用不受支持,则此方法返回一个空格“”。 返回值: 引用字符串,如果引用不受支持,则返回一个空格。 27. public String getSQLKeywords() 功能: 获取此数据库的还不是 SQL:2003 关键字的所有 SQL 关键字的逗号分隔列表。 返回值: 此数据库的还不是 SQL:2003 关键字的那些关键字组成的列表。 161 第9章 JDBC 元数据处理 28. public String getNumericFunctions() 功能: 获取可用于此数据库的数学函数的逗号分隔列表。这些是用于 JDBC 函数转义子句中的 Open /Open CLI 数学 函数名称。 返回值: 此数据库支持的数学函数的列表。 29. public String getStringFunctions() 功能: 获取可用于此数据库的字符串函数的逗号分隔列表。这些是用于 JDBC 函数转义子句中的 Open Group CLI 字 符串函数名称。 返回值: 受此数据库支持的字符串函数的列表。 30. public String getSystemFunctions() 功能: 获取可用于此数据库的系统函数的逗号分隔列表。这些是用于 JDBC 函数转义子句中的 Open Group CLI 系统 函数名称。 返回值: 受此数据库支持的系统函数的列表。 31. public String getTimeDateFunctions() 功能: 获取可用于此数据库的时间和日期函数的逗号分隔列表。 返回值: 受此数据库支持的时间和日期函数的列表。 32. public String getSearchStringEscape() 功能: 获取可用于转义通配符的字符串。该字符串是可用于在类别搜索参数中转义’_’ 或’%’ 的字符串,这些类别搜索 参数表示模式(因此使用通配符之一)。 返回值: 用于转义通配符的字符串。 33. public String getExtraNameCharacters() 功能: 获取可以在不带引号的标识符名称中使用的所有“额外”字符(除了 a-z、A-Z、0-9 和 _ 以外的字符)。 162 第9章 JDBC 元数据处理 返回值: 包含额外字符的字符串。 34. public boolean supportsAlterTableWithAddColumn() 功能: 获取此数据库是否支持带有 add 列的 ALTER TABLE。 返回值: 如果是这样,则返回 true;否则返回 false 。 35. public boolean supportsAlterTableWithDropColumn() 功能: 获取此数据库是否支持带有 drop 列的 ALTER TABLE。 返回值: 如果是这样,则返回 true;否则返回 false 。 36. public boolean supportsColumnAliasing() 功能: 获取此数据库是否支持为列提供别名。 返回值: 如果是这样,则返回 true;否则返回 false 。 37. public boolean nullPlusNonNullIsNull() 功能: 获取此数据库是否支持 NULL 值与等于 NULL 的非 NULL 值之间的连接。 返回值: 如果是这样,则返回 true;否则返回 false 。 38. public boolean supportsConvert() 功能: 获取此数据库是否支持用于 JDBC 类型之间转换的 JDBC 标量函数 CONVERT。JDBC 类型是 java.sql.Types 中定义的一般 SQL 数据类型。 返回值: 如果是这样,则返回 true;否则返回 false。 39. public boolean supportsTableCorrelationNames() 功能: 获取此数据库是否支持表关联名称。 163 第9章 JDBC 元数据处理 返回值: 如果是这样,则返回 true;否则返回 false 。 40. public boolean supportsDifferentTableCorrelationNames() 功能: 获取在表关联名称受支持时,是否要限制它们与表的名称不同。 返回值: 如果是这样,则返回 true;否则返回 false 。 41. public boolean supportsExpressionsInOrderBy() 功能: 获取此数据库是否支持 ORDER BY 列表中的表达式。 返回值: 如果是这样,则返回 true;否则返回 false 。 42. public boolean supportsOrderByUnrelated() 功能: 获取此数据库是否支持使用不在 SELECT 语句中而在 ORDER BY 子句中的列。 返回值: 如果是这样,则返回 true;否则返回 false 。 43. public boolean supportsGroupBy() 功能: 获取此数据库是否支持某种形式的 GROUP BY 子句。 返回值: 如果是这样,则返回 true;否则返回 false 。 44. public boolean supportsGroupByUnrelated() 功能: 获取此数据库是否支持使用不在 SELECT 语句中而在 GROUP BY 子句中的列。 返回值: 如果是这样,则返回 true;否则返回 false 。 45. public boolean supportsGroupByBeyondSelect() 功能: 获取此数据库是否支持使用不包含在 SELECT 语句中而包含在 GROUP BY 子句中的列,假设 SELECT 语句 中的所有列都包含在 GROUP BY 子句中。 164 第9章 JDBC 元数据处理 返回值: 如果是这样,则返回 true;否则返回 false 。 46. public boolean supportsLikeEscapeClause() 功能: 获取此数据库是否支持指定 LIKE 转义子句。 返回值: 如果是这样,则返回 true;否则返回 false 。 47. public boolean supportsMultipleResultSets() 功能: 获取此数据库是否支持一次调用 execute 方法获得多个 ResultSet 对象。 返回值: 如果是这样,则返回 true;否则返回 false 。 48. public boolean supportsMultipleTransactions() 功能: 获取此数据库是否允许一次打开多个事务(在不同的 connection 上)。 返回值: 如果是这样,则返回 true;否则返回 false 。 49. public boolean supportsNonNullableColumns() 功能: 获取是否可以将此数据库中的列定义为非 null。 返回值: 如果是这样,则返回 true;否则返回 false 。 50. public boolean supportsMinimumSQLGrammar() 功能: 获取此数据库是否支持 ODBC Minimum SQL 语法。 返回值: 如果是这样,则返回 true;否则返回 false 。 51. public boolean supportsCoreSQLGrammar() 功能: 获取此数据库是否支持 ODBC Core SQL 语法。 返回值: 165 第9章 JDBC 元数据处理 如果是这样,则返回 true;否则返回 false 。 52. public boolean supportsExtendedSQLGrammar() 功能: 获取此数据库是否支持 ODBC Extended SQL 语法。 返回值: 如果是这样,则返回 true;否则返回 false 。 53. public boolean supportsANSI92EntryLevelSQL() 功能: 获取此数据库是否支持 ANSI92 入门级 SQL 语法。 返回值: 如果是这样,则返回 true;否则返回 false 。 54. public boolean supportsANSI92IntermediateSQL() 功能: 获取此数据库是否支持受支持的 ANSI92 中间 SQL 语法。 返回值: 如果是这样,则返回 true;否则返回 false 。 55. public boolean supportsANSI92FullSQL() 功能: 获取此数据库是否支持受支持的 ANSI92 完全 SQL 语法。 返回值: 如果是这样,则返回 true;否则返回 false 。 56. public boolean supportsIntegrityEnhancementFacility() 功能: 获取此数据库是否支持 SQL Integrity Enhancement Facility。 返回值: 如果是这样,则返回 true;否则返回 false 。 57. public boolean supportsOuterJoins() 功能: 获取此数据库是否支持某种形式的外连接。 返回值: 如果是这样,则返回 true;否则返回 false 。 166 第9章 JDBC 元数据处理 58. public boolean supportsFullOuterJoins() 功能: 获取此数据库是否支持完全嵌套的外连接。 返回值: 如果是这样,则返回 true;否则返回 false 。 59. public boolean supportsLimitedOuterJoins() 功能: 获取此数据库是否为外连接提供受限制的支持。(如果 supportsFullOuterJoins 方法返回 true,则此为 true)。 返回值: 如果是这样,则返回 true;否则返回 false 。 60. public String getSchemaTerm() 功能: 获取数据库供应商用于”schema” 的首选术语。 返回值: 供应商用于”schema” 的术语。 61. public String getProcedureTerm() 功能: 获取数据库供应商用于”procedure” 的首选术语。 返回值: 供应商用于”procedure” 的术语。 62. public String getCatalogTerm() 功能: 获取数据库供应商用于”catalog” 的首选术语。 返回值: 供应商用于”catalog” 的术语。 63. public boolean isCatalogAtStart() 功能: 获取某个类别是否出现在完全限定表名的开头。如果没有出现在开头,则类别出现在表名末尾。 返回值: 如果类别出现在完全限定表名的开头,则返回 true;否则返回 false 。 167 第9章 JDBC 元数据处理 64. public String getCatalogSeparator() 功能: 获取此数据库用作类别和表名之间的分隔符的 String。 返回值: 分隔符字符串。 65. public boolean supportsSchemasInDataManipulation() 功能: 获取某个模式名称是否可以在数据操作语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 66. public boolean supportsSchemasInProcedureCalls() 功能: 获取某个模式名称是否可以在过程调用语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 67. public boolean supportsSchemasInTableDefinitions() 功能: 获取某个模式名称是否可以在表定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 68. public boolean supportsSchemasInIndexDefinitions() 功能: 获取某个模式名称是否可以在获取定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 69. public boolean supportsSchemasInPrivilegeDefinitions() 功能: 获取某个模式名称是否可以在特权定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 168 第9章 JDBC 元数据处理 70. public boolean supportsCatalogsInDataManipulation() 功能: 获取某个类别名称是否可以在数据操作语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 71. public boolean supportsCatalogsInProcedureCalls() 功能: 获取某个类别名称是否可以在过程调用语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 72. public boolean supportsCatalogsInTableDefinitions() 功能: 获取某个类别名称是否可以在表定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 73. public boolean supportsCatalogsInIndexDefinitions() 功能: 获取某个类别名称是否可以在获取定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 74. public boolean supportsCatalogsInPrivilegeDefinitions() 功能: 获取某个类别名称是否可以在特权定义语句中使用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 75. public boolean supportsPositionedDelete() 功能: 获取此数据库是否支持位置的 DELETE 语句。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 169 第9章 JDBC 元数据处理 76. public boolean supportsPositionedUpdate() 功能: 获取此数据库是否支持位置的 UPDATE 语句。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 77. public boolean supportsSelectForUpdate() 功能: 获取此数据库是否支持位置的 SELECT FOR UPDATE 语句。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 78. public boolean supportsStoredProcedures() 功能: 获取此数据库是否支持使用存储过程转义语法的存储过程调用。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 79. public boolean supportsSubqueriesInComparisons() 功能: 获取此数据库是否支持比较表达式中的子查询。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 80. public boolean supportsSubqueriesInExists() 功能: 获取此数据库是否支持 EXISTS 表达式中的子查询。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 81. public boolean supportsSubqueriesInIns() 功能: 获取此数据库是否支持 IN 表达式中的子查询。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 170 第9章 JDBC 元数据处理 82. public boolean supportsSubqueriesInQuantifieds() 功能: 获取此数据库是否支持量化表达式 (quantified expression) 中的子查询。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 83. public boolean supportsCorrelatedSubqueries() 功能: 获取此数据库是否支持相关子查询。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 84. public boolean supportsUnion() 功能: 获取此数据库是否支持 SQL UNION。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 85. public boolean supportsUnionAll() 功能: 获取此数据库是否支持 SQL UNION ALL。 返回值: 如果模式名称可以在数据操作语句中使用,则返回 true;否则返回 false 。 86. public boolean supportsOpenCursorsAcrossCommit() 功能: 获取此数据库是否支持在进行提交期间保持游标开放。 返回值: 如果语句总是保持开放,则返回 true;如果游标可能无法保持开放,则返回 false。 87. public boolean supportsOpenCursorsAcrossRollback() 功能: 获取此数据库是否支持在回滚期间保持游标开放。 返回值: 如果语句总是保持开放,则返回 true;如果游标可能无法保持开放,则返回 false 。 171 第9章 JDBC 元数据处理 88. public boolean supportsOpenStatementsAcrossCommit() 功能: 获取此数据库是否支持在进行提交期间保持语句开放。 返回值: 如果语句总是保持开放,则返回 true;如果游标可能无法保持开放,则返回 false 。 89. public boolean supportsOpenStatementsAcrossRollback() 功能: 获取此数据库是否支持在回滚期间保持语句开放。 返回值: 如果语句总是保持开放,则返回 true;如果游标可能无法保持开放,则返回 false 。 90. public int getMaxBinaryLiteralLength() 功能: 获取此数据库允许在内嵌二进制字面值中使用的最大十六进制字符数。 返回值: max,即用于二进制字面值的最大长度(十六进制字符形式);结果为零意味着没有限制或限制是未知的。 91. public int getMaxCharLiteralLength() 功能: 获取此数据库允许用于字符字面值的最大字符数。 返回值: 允许用于字符字面值的最大字符数;结果为零意味着没有限制或限制是未知的。 92. public int getMaxColumnNameLength() 功能: 获取此数据库允许用于列名称的最大字符数。 返回值: 允许用于列名称的最大字符数;结果为零意味着没有限制或限制是未知的。 93. public int getMaxColumnsInGroupBy() 功能: 获取此数据库允许在 GROUP BY 子句中使用的最大列数。 返回值: 所允许的最大列数;结果为零意味着没有限制或限制是未知的。 172 第9章 JDBC 元数据处理 94. public int getMaxColumnsInIndex() 功能: 获取此数据库允许在索引中使用的最大列数。 返回值: 所允许的最大列数;结果为零意味着没有限制或限制是未知的。 95. public int getMaxColumnsInOrderBy() 功能: 获取此数据库允许在 ORDER BY 子句中使用的最大列数。 返回值: 所允许的最大列数;结果为零意味着没有限制或限制是未知的。 96. public int getMaxColumnsInSelect() 功能: 获取此数据库允许在 SELECT 列表中使用的最大列数。 返回值: 所允许的最大列数;结果为零意味着没有限制或限制是未知的。 97. public int getMaxColumnsInTable() 功能: 获取此数据库允许在表中使用的最大列数。 返回值: 所允许的最大列数;结果为零意味着没有限制或限制是未知的。 98. public int getMaxConnections() 功能: 获取连接到此数据库的并发连接的可能最大数。 返回值: 在某一时间可能的活动连接的最大数;结果为零意味着没有限制或限制是未知的。 99. public int getMaxCursorNameLength() 功能: 获取此数据库允许用于游标名称的最大字符数。 返回值: 允许用于游标名称的最大字符数;结果为零意味着没有限制或限制是未知的。 173 第9章 JDBC 元数据处理 100. public int getMaxIndexLength() 功能: 获取此数据库允许用于索引(包括索引的所有部分)的最大字节数。 返回值: 所允许的最大字节数;这一限制由该索引所有组成部分的组成;结果为零意味着没有限制或者限制是未知的。 101. public int getMaxSchemaNameLength() 功能: 获取此数据库允许在模式名称中使用的最大字符数。 返回值: 允许用于模式名称的最大字符数;结果为零意味着没有限制或限制是未知的。 102. public int getMaxProcedureNameLength() 功能: 获取此数据库允许用于过程名称的最大字符数。 返回值: 允许用于过程名称的最大字符数;结果为零意味着没有限制或限制是未知的。 103. public int getMaxCatalogNameLength() 功能: 获取此数据库允许用于类别名称的最大字符数。 返回值: 允许用于类别名称的最大字符数;结果为零意味着没有限制或限制是未知的。 104. public int getMaxRowSize() 功能: 获取此数据库允许在单行中使用的最大字节数。 返回值: 允许在行中使用的最大字节数;结果为零意味着没有限制或限制是未知的。 105. public boolean doesMaxRowSizeIncludeBlobs() 功能: 获取 getMaxRowSize 方法的返回值是否包括 SQL 数据类型 LONGVARCHAR 和 LONGVARBINARY。 返回值: 如果是这样,则返回 true;否则返回 false 。 174 第9章 JDBC 元数据处理 106. public int getMaxStatementLength() 功能: 获取此数据库允许在 SQL 语句中使用的最大字符数。 返回值: 允许在 SQL 语句中使用的最大字符数;结果为零意味着没有限制或限制是未知的。 107. public int getMaxStatements() 功能: 获取在此数据库中在同一时间内可处于开放状态的最大活动语句数。 返回值: 在某一时间可同时处于开放状态的最大语句数;结果为零意味着没有限制或限制是未知的。 108. public int getMaxTableNameLength() 功能: 获取此数据库允许在表名称中使用的最大字符数。 返回值: 允许用于表名称的最大字符数;结果为零意味着没有限制或限制是未知的。 109. public int getMaxTablesInSelect() 功能: 获取此数据库允许在 SELECT 语句中使用的表的最大数量。 返回值: 允许在 SELECT 语句中使用的表的最大数量;结果为零意味着没有限制或限制是未知的。 110. public int getMaxUserNameLength() 功能: 获取此数据库允许在用户名称中使用的最大字符数。 返回值: 允许用于用户名称的最大字符数;结果为零意味着没有限制或限制是未知的。 111. public int getDefaultTransactionIsolation() 功能: 获取此数据库的默认事务隔离级别。java.sql.Connection 中定义了一些可能值。 返回值: 默认隔离级别。 175 第9章 JDBC 元数据处理 112. public boolean supportsTransactions() 功能: 获取此数据库是否支持事务。如果不支持,则调用 commit 方法是无操作 (noop),并且隔离级别是 TRANSACTION_NONE。 返回值: 如果事务受支持,则返回 true;否则返回 false 。 113. public boolean supportsTransactionIsolationLevel(int level) 功能: 获取此数据库是否支持给定事务隔离级别。 参数: level - java.sql.Connection 中定义的事务隔离级别之一。 返回值: 如果是这样,则返回 true;否则返回 false 。 114. public boolean supportsDataDefinitionAndDataManipulationTransactions() 功能: 获取此数据库是否同时支持事务中的数据定义和数据操作语句。 返回值: 如果是这样,则返回 true;否则返回 false 。 115. public boolean supportsDataManipulationTransactionsOnly() 功能: 获取此数据库是否仅支持事务中的数据操作语句。 返回值: 如果是这样,则返回 true;否则返回 false 。 116. public boolean dataDefinitionCausesTransactionCommit() 功能: 获取事务中的数据定义语句是否强迫该事务进行提交。 返回值: 如果是这样,则返回 true;否则返回 false 。 117. public boolean dataDefinitionIgnoredInTransactions() 功能: 获取此数据库是否忽略事务中的数据定义语句。 176 第9章 JDBC 元数据处理 返回值: 如果是这样,则返回 true;否则返回 false 。 118. public ResultSet getProcedures(String catalog,String schemaPattern,String procedureNamePattern) 功能: 获取可在给定类别中使用的存储过程的描述。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 procedureNamePattern - 过程名称模式;它必须与存储在数据库中的过程名称匹配。 返回值: ResultSet - 每个行都是一个过程描述。 119. public ResultSet getProcedureColumns(String catalog,String schemaPattern,String procedureNamePattern,String columnNamePattern) 功能: 获取给定类别的存储过程参数和结果列的描述。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 则获取没有类别的描述,表示获取 没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 procedureNamePattern - 过程名称模式;它必须与存储在数据库中的过程名称匹配。 columnNamePattern - 列名称模式;它必须与存储在数据库中的列名称匹配。 返回值: ResultSet - 每一行都描述一个存储过程参数或列。 120. public ResultSet getTables(String catalog,String schemaPattern,String tableNamePattern,String[] types) 功能: 获取可在给定类别中使用的表的描述。仅返回与类别、模式、表名称和类型标准匹配的表描述。它们根据 TABLE_TYPE、TABLE_CAT、TABLE_SCHEM 和 TABLE_NAME 进行排序。 参数: 177 第9章 JDBC 元数据处理 catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 tableNamePattern - 表名称模式;它必须与存储在数据库中的表名称匹配。 types - 要包括的表类型所组成的列表,必须取自从 getTableTypes() 返回的表类型列表;null 表示返回所有类 型。 返回值: ResultSet - 每一行都是一个表描述。 121. public ResultSet getSchemas() 功能: 获取可在此数据库中使用的模式名称。可根据 TABLE_CATALOG 和 TABLE_SCHEM 对结果进行排序。 返回值: ResultSet 对象,在该对象中,每一行都是一个模式描述。 122. public ResultSet getCatalogs() 功能: 获取可在此数据库中使用的类别名称。可根据类别名称对结果进行排序。 返回值: ResultSet 对象,在该对象中,每一行都有一个作为类别名称的 String 列。 123. public ResultSet getTableTypes() 功能: 获取可在此数据库中使用的表类型。可根据表类型对结果进行排序。 返回值: ResultSet 对象,在该对象中,每一行都有一个作为表类型的 String 列。 124. public ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern) 功能: 获取可在指定类别中使用的表列的描述。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 178 第9章 JDBC 元数据处理 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 tableNamePattern - 表名称模式;它必须与存储在数据库中的表名称匹配。 columnNamePattern - 列名称模式;它必须与存储在数据库中的列名称匹配。 返回值: ResultSet - 每一行都是一个列描述。 125. public ResultSet getColumnPrivileges(String catalog,String schema,String table,String columnNamePattern) 功能: 获取用于表列的访问权的描述。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配; columnNamePattern - 列名称模式;它必须与存储在数据库中的列名称匹配。 返回值: ResultSet - 每一行都是一个列特权描述。 126. public ResultSet getTablePrivileges(String catalog,String schemaPattern,String tableNamePattern) 功能: 获取可在类别中使用的每个表的访问权的描述。注意,表特权可用于表中的一个或多个列。假定此特权可用于 所有列是错误的(对于某些系统可能是正确的,但并非所有的系统都如此)。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 tableNamePattern - 表名称模式;它必须与存储在数据库中的表名称匹配。 返回值: ResultSet - 每个行都是一个表特权描述。 127. public ResultSet getBestRowIdentifier(String catalog,String schema,String table,int scope,boolean nullable) 功能: 179 第9章 JDBC 元数据处理 获取唯一标识行的表的最佳列集合的描述。它们根据 SCOPE 进行排序。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配。 scope - 感兴趣的作用域,可使用于 SCOPE 相同的值。 nullable - 包含可为 null 的列。 返回值: ResultSet - 每一行都是一个列描述。 128. public ResultSet getVersionColumns(String catalog,String schema,String table) 功能: 获取在更新行中的任意值时自动更新的表列的描述。它们是无序的。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配。 返回值: 一个 ResultSet 对象,在该对象中,每一行都是一个列描述。 129. public ResultSet getPrimaryKeys(String catalog,String schema,String table) 功能: 获取对给定表的主键列的描述。它们根据 COLUMN_NAME 进行排序。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配。 返回值: 180 第9章 JDBC 元数据处理 ResultSet - 每一行都是一个主键列描述。 130. public ResultSet getImportedKeys(String catalog,String schema,String table) 功能: 获 取 由 给 定 表 的 外 键 列 (表 导 入 的 主 键) 引 用 的 主 键 列 的 描 述。 它 们 根 据 PKTABLE_CAT、PK- TABLE_SCHEM、PKTABLE_NAME 和 KEY_SEQ 进行排序。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配。 返回值: ResultSet - 每一行都是一个主键列描述。 131. public ResultSet getExportedKeys(String catalog,String schema,String table) 功能: 获 取 引 用 给 定 表 的 主 键 列 (表 导 入 的 外 键) 的 外 键 列 的 描 述。 它 们 根 据 FKTABLE_CAT、FK- TABLE_SCHEM、FKTABLE_NAME 和 KEY_SEQ 进行排序。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配。 返回值: 一个 ResultSet 对象,在该对象中,每一行都是一个外键列描述。 132. public ResultSet getCrossReference(String parentCatalog,String parentSchema,String parentTable,String foreignCatalog,String foreignSchema,String foreignTable) 功能: 获 取 给 定 外 键 列 表 中 外 键 列 的 描 述, 这 些 列 引 用 主 键 或 表 示 父 表 (可 能 是 相 同 的 表, 也 可 能 是 不 同 的 表) 唯 一 约 束 的 列。 从 父 表 返 回 的 列 数 必 须 与 组 成 外 键 的 列 数 匹 配。 它 们 根 据 FKTABLE_CAT、FK- TABLE_SCHEM、FKTABLE_NAME 和 KEY_SEQ 进行排序。 参数: 181 第9章 JDBC 元数据处理 parentCatalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描 述;为 null 则表示该类别名称不应该用于缩小搜索范围。 parentSchema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描 述;为 null 则表示该模式名称不应该用于缩小搜索范围。 parentTable - 导出该键的表的名称;它必须与存储在数据库中的表名称匹配; foreignCatalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 则获取没有类别的那些描 述,为 null 则表示从选择标准中删除类别名称。 foreignSchema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取那些没有模式的描 述,为 null 则表示从选择标准中删除模式名称。 foreignTable - 导入该键的表的名称;它必须与存储在数据库中的表名称匹配。 返回值: ResultSet - 每一行是一个外键列描述。 133. public ResultSet getTypeInfo() 功能: 获取此数据库支持的所有数据类型的描述。它们先按照 DATA_TYPE 排序,然后按照数据类型映射表与相应 的 JDBC SQL 类型的接近程度排序。 返回值: ResultSet 对象,在此对象中,每一行都是一个 SQL 类型描述。 134. public ResultSet getIndexInfo(String catalog,String schema,String table,boolean unique,boolean approximate) 功能: 获取给定表的索引和统计信息的描述。它们根据 NON_UNIQUE、TYPE、INDEX_NAME 和 ORDINAL_POSITION 进行排序。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schema - 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 table - 表名称;它必须与存储在数据库中的表名称匹配; unique - 该参数为 true 时,仅返回唯一值的索引;该参数为 false 时,返回所有索引,不管它们是否唯一。 approximate - 该参数为 true 时,允许结果是接近的数据值或这些数据值以外的值;该参数为 false 时,要求结 果是精确结果。 返回值: ResultSet - 每一行都是一个索引列描述。 182 第9章 JDBC 元数据处理 135. public boolean supportsResultSetType(int type) 功能: 获取此数据库是否支持给定结果集类型。 参数: type - 在 java.sql.ResultSet 中定义。 返回值: 如果是这样,则返回 true;否则返回 false。 136. public boolean supportsResultSetConcurrency(int type,int concurrency) 功能: 获取此数据库是否支持与给定结果集类型结合在一起的给定并发性类型。 参数: type - 在 java.sql.ResultSet 中定义。 concurrency - java.sql.ResultSet 中定义的类型。 返回值: 如果支持,则返回 true;否则返回 false 。 137. public boolean ownUpdatesAreVisible(int type) 功能: 获取对于给定类型的 ResultSet 对象,结果集自身的更新是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果更新对于给定结果集是可见的,则返回 true;否则返回 false 。 138. public boolean ownDeletesAreVisible(int type) 功能: 获取结果集自身的删除是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果删除对于给定结果集是可见的,则返回 true;否则返回 false 。 183 第9章 JDBC 元数据处理 139. public boolean ownInsertsAreVisible(int type) 功能: 获取结果集自身的插入是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果插入对于给定结果集是可见的,则返回 true;否则返回 false 。 140. public boolean othersUpdatesAreVisible(int type) 功能: 获取由其他结果集类型进行的更新是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果由其他结果集类型进行的更新对于给定结果集是可见的,则返回 true;否则返回 false 。 141. public boolean othersDeletesAreVisible(int type) 功能: 获取由其他结果集类型进行的删除是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果由其他结果集类型进行的删除对于给定结果集是可见的,则返回 true;否则返回 false 。 142. public boolean othersInsertsAreVisible(int type) 功能: 获取由其他结果集类型进行的插入是否可见。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果由其他结果集类型进行的插入对于给定结果集是可见的,则返回 true;否则返回 false 。 184 第9章 JDBC 元数据处理 143. public boolean updatesAreDetected(int type) 功能: 获取是否可以通过调用 ResultSet.rowUpdated 方法检测可见行的更新。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果根据结果集类型检测更改,则返回 true;否则返回 false 。 144. public boolean deletesAreDetected(int type) 功能: 获取是否可以通过调用 ResultSet.rowDeleted 方法检测可见行的删除。如果 deletesAreDetected 方法返回 false,则意味着从结果集中移除已删除的行。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果根据给定结果集类型检测删除,则返回 true;否则返回 false 。 145. public boolean insertsAreDetected(int type) 功能: 获取是否可以通过调用 ResultSet.rowInserted 方法检测可见行的插入。 参数: type - ResultSet 类 型, 它 是 ResultSet.TYPE_FORWARD_ONLY、Result- Set.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一。 返回值: 如果根据指定结果集类型检测更改,则返回 true;否则返回 false。 146. public boolean supportsBatchUpdates() 功能: 获取此数据库是否支持批量更新。 返回值: 如果此数据库支持批量更新,则返回 true;否则返回 false 。 147. public ResultSet getUDTs(String catalog,String schemaPattern,String typeNamePattern,int[] types) 功能: 185 第9章 JDBC 元数据处理 获取在特定模式中定义的用户定义类型 (UDT) 的描述。特定于模式的 UDT 可能具有 JAVA_OBJECT、 STRUCT 或 DISTINCT 类型。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 typeNamePattern - 类型名称模式;它必须与存储在数据库中的类型名称匹配,它可以是一个完全限定名称; types - 将包括的用户定义类型(JAVA_OBJECT、STRUCT 或 DISTINCT)组成的列表;该参数为 null 则返 回所有类型。 返回值: ResultSet 对象,其中每一行都描述了一个 UDT 。 148. public Connection getConnection() 功能: 获取此元数据对象所产生的连接。 返回值: 此元数据对象所产生的连接。 149. public boolean supportsSavepoints() 功能: 获取此数据库是否支持保存点 (savepoint)。 返回值: 如果保存点受支持,则返回 true;否则返回 false 。 150. public boolean supportsNamedParameters() 功能: 获取此数据库是否支持可调用语句的指定参数。 返回值: 如果指定参数受支持,则返回 true;否则返回 false 。 151. public boolean supportsMultipleOpenResults() 功能: 获取是否可以同时拥有从 CallableStatement 对象中返回的多个 ResultSet 对象。 返回值: 如果一个 CallableStatement 对象可以同时返回多个 ResultSet 对象,则返回 true;否则返回 false 。 186 第9章 JDBC 元数据处理 152. public boolean supportsGetGeneratedKeys() 功能: 获取是否可以在执行语句后获取自动生成的键。 返回值: 如果可以在已执行语句后获取自动生成的键,则返回 true;否则返回 false 。 如果返回 true,则 JDBC 驱动程序至少必须为 SQL INSERT 语句支持自动生成键的返回值。 153. public ResultSet getSuperTypes(String catalog,String schemaPattern,String typeNamePattern) 功能: 获取在此数据库的特定模式中定义的用户定义类型 (UDT) 分层结构的描述。仅建模直接的超类型/子类型关 系。 参数: catalog - 类别名称,该参数为”” 表示获取没有类别的那些描述,为 null 则表示从选择标准中删除类别名称。 schemaPattern - 模式名称的模式,该参数为”” 表示获取没有模式的那些描述。 typeNamePattern - UDT 名称模式,可以是一个完全限定名称。 返回值: ResultSet 对象,其中一行给出了关于指定 UDT 的信息。 154. public ResultSet getSuperTables(String catalog,String schemaPattern,String tableNamePattern) 功能: 获取在此数据库的特定模式中定义的表分层结构的描述。 参数: catalog - 类别名称,该参数为”” 表示获取没有类别的那些描述,为 null 则表示从选择标准中删除类别名称。 schemaPattern - 模式名称的模式,该参数为”” 表示获取没有模式的那些描述。 tableNamePattern - 表名称模式,可以是一个完全限定名称。 返回值: 一个 ResultSet 对象,其中的每一行都是一个类型描述。 155. public ResultSet getAttributes(String catalog,String schemaPattern,String typeNamePattern,String attributeNamePattern) 功能: 获取可在给定模式和类别中使用的用户定义类型 (UDT) 的给定类型的给定属性的描述。 参数: 187 第9章 JDBC 元数据处理 catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为”” 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为”” 表示获取没有模式的 那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。 typeNamePattern - 类型名称模式;它必须与存储在数据库中的类型名称匹配。 attributeNamePattern - 属性名称模式;它必须与在数据库中被声明的属性名称匹配。 返回值: 一个 ResultSet 对象,其中每一行都是一个属性描述。 156. public boolean supportsResultSetHoldability(int holdability) 功能: 获取此数据库是否支持给定结果集可保存性。 参数: holdability - 以 下 常 量 之 一:ResultSet.HOLD_CURSORS_OVER_COMMIT 或 Result- Set.CLOSE_CURSORS_AT_COMMIT 。 返回值: 如果支持,则返回 true;否则返回 false 。 157. public int getResultSetHoldability() 功能: 针对 ResultSet 对象获取此数据库的默认可保存性。 返回值: 默 认 可 保 存 性, 它 是 ResultSet.HOLD_CURSORS_OVER_COMMIT 或 Result- Set.CLOSE_CURSORS_AT_COMMIT 。 158. public int getDatabaseMajorVersion() 功能: 获取底层数据库的主版本号。 返回值: 底层数据库的主版本号。 159. public int getDatabaseMinorVersion() 功能: 底层数据库的次版本号。 返回值: 底层数据库的次版本号。 188 第9章 JDBC 元数据处理 160. public int getJDBCMajorVersion() 功能: 获取此驱动程序的主 JDBC 版本号。 返回值: JDBC 的主版本号。 161. public int getJDBCMinorVersion() 功能: 获取此驱动程序的次 JDBC 版本号。 返回值: JDBC 的次版本号。 162. public int getSQLStateType() 功能: 指示由 SQLException.getSQLState 返回的 SQLSTATE 是 X/Open(现在称为 Open Group)SQL CLI 还是 SQL:2003。 返回值: SQLSTATE 的类型,它为 sqlStateXOpen 或 sqlStateSQL 之一。 163. public boolean locatorsUpdateCopy() 功能: 指示对 LOB 的更新是在副本上进行还是直接更新到 LOB。 返回值: 如果更新在 LOB 的副本上进行,则返回 true;如果直接更新到 LOB,则返回 false 。 164. public boolean supportsStatementPooling() 功能: 获取此数据库是否支持语句合并 (statement pooling)。 返回值: 如果支持,则返回 true;否则返回 false 。 165. public ResultSet getFunctions(String catalog,String schemaPattern,String functionNamePattern) 功能: 获取给定类别中可用的系统和用户函数的描述。 参数: 189 第9章 JDBC 元数据处理 catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;为”” 表示获取没有类别的那些描述;为 null 表 示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;为”” 表示获取没有模式的那些描 述;为 null 表示该模式名称不应该用于缩小搜索范围。 functionNamePattern - 函数名称模式;它必须与存储在数据库中的函数名称匹配。 返回值: ResultSet - 每行是一个函数描述。 166. public ResultSet getFunctionColumns(String catalog,String schemaPattern,String functionNamePattern,String columnNamePattern) 功能: 获取给定类别的系统或用户函数参数和返回类型的描述。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;为”” 表示获取没有类别的那些描述;为 null 表 示该类别名称不应该用于缩小搜索范围。 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;为”” 表示获取没有模式的那些描 述;为 null 表示该模式名称不应该用于缩小搜索范围。 functionNamePattern - 进程名称模式;它必须与存储在数据库中的函数名称匹配。 columnNamePattern - 参数名称模式;它必须与存储在数据库中的参数或列名称匹配。 返回值: ResultSet - 每行描述一个用户函数参数、列或返回类型。 9.6 JDBC ParameterMetaData API a. public int getParameterCount() 功能: 获取 PreparedStatement 对象中的参数的数量,此 ParameterMetaData 对象包含了该对象的信息。 返回值: 参数的数量。 b. public int isNullable(int param) 功能: 获取是否允许在指定参数中使用 null 值。 参数: 190 第9章 JDBC 元数据处理 param - 第一个参数是 1,第二个参数是 2,…… 返回值: 给定参数的状态是否可为 null, 该 状 态 值 是 ParameterMetaData.parameterNoNulls、ParameterMeta- Data.parameterNullable 或 ParameterMetaData.parameterNullableUnknown 之一。 c. public boolean isSigned(int param) 功能: 获取指定参数的值是否可以是带符号的数字。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 d. public int getPrecision(int param) 功能: 获取指定参数的指定列大小。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 精度。 e. public int getScale(int param) 功能: 获取指定参数的小数点右边的位数。对于标度不可用的数据类型,则返回 0。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 精度。 f. public int getParameterType(int param) 功能: 获取指定参数的 SQL 类型。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 191 第9章 JDBC 元数据处理 来自 java.sql.Types 的 SQL 类型。 g. public String getParameterTypeName(int param) 功能: 获取指定参数的特定于数据库的类型名称。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 数据库使用的类型名称。如果参数类型是用户定义的类型,则返回完全限定的类型名称。 h. public String getParameterClassName(int param) 功能: 获取 Java 类的完全限定名称,该类的实例应该传递给 PreparedStatement.setObject 方法。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: Java 编程语言中的类的完全限定名称,方法 PreparedStatement.setObject 将使用该名称设置指定参数中的值。 此为用于自定义映射关系的类名称。 i. public int getParameterMode(int param) 功能: 获取指定参数的模式。 参数: param - 第一个参数是 1,第二个参数是 2,…… 返回值: 参数的模式,该模式是 ParameterMetaData.parameterModeIn、ParameterMetaData.parameterModeOut、ParameterMetaData.parameterModeInOut 或 ParameterMetaData.parameterModeUnknown 之一。 9.7 JDBC ResultSetMetaData API a. public int getColumnCount() 功能: 返回此 ResultSet 对象中的列数。 返回值: 192 第9章 JDBC 元数据处理 列数。 b. public boolean isAutoIncrement(int column) 功能: 指示是否自动为指定列进行编号。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 c. public boolean isCaseSensitive(int column) 功能: 指示列的大小写是否有关系。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 d. public boolean isSearchable(int column) 功能: 指示是否可以在 where 子句中使用指定的列。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 e. public boolean isCurrency(int column) 功能: 指示指定的列是否是一个哈希代码值。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 193 第9章 JDBC 元数据处理 f. public int isNullable(int column) 功能: 指示指定列中的值是否可以为 null。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 给定列的状态是否可以为 null 的判断,此状态值是 columnNoNulls、columnNullable 或 columnNullableUnknown 之一。 g. public boolean isSigned(int column) 功能: 指示指定列中的值是否带正负号。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 h. public int getColumnDisplaySize(int column) 功能: 指示指定列的最大标准宽度,以字符为单位。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 允许作为指定列宽度的最大标准字符数。 i. public String getColumnLabel(int column) 功能: 获取用于打印输出和显示的指定列的建议标题。建议标题通常由 SQL AS 子句来指定。如果未指定 SQL AS, 则从 getColumnLabel 返回的值将和 getColumnName 方法返回的值相同。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 建立列标题。 194 第9章 JDBC 元数据处理 j. public String getColumnName(int column) 功能: 获取指定列的名称。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 列名称。 k. public String getSchemaName(int column) 功能: 获取指定列的表模式。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 模式名称;如果没有可应用的名称,则返回””。 l. public int getPrecision(int column) 功能: 获取指定列的指定列宽。对于数值型数据,是指最大精度。对于字符型数据,是指字符串长度。对于日期时间 的数据类型,是指 String 表示形式的字符串长度(假定为最大允许的小数秒组件)。对于二进制型数据,是指 字节长度。对于 ROWID 数据类型,是指字节长度。对于其列大小不可用的数据类型,则返回 0。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 精度。 m. public int getScale(int column) 功能: 获取指定列的小数点右边的位数。对于其标度不可用的数据类型,则返回 0。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 标度。 195 第9章 JDBC 元数据处理 n. public String getTableName(int column) 功能: 获取指定列的名称。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 表名称;如果没有可应用的名称,则返回”” 。 o. public String getCatalogName(int column) 功能: 获取指定列的表目录名称。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 在其中显示给定列的表的目录名称;如果可应用的名称,则返回”” 。 p. public int getColumnType(int column) 功能: 获取指定列的 SQL 类型。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 来自 java.sql.Types 的 SQL 类型。 q. public String getColumnTypeName(int column) 功能: 获取指定列的数据库特定的类型名称。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 数据库使用的类型名称。如果列类型是用户定义的类型,则返回完全限定的类型名称。 r. public boolean isReadOnly(int column) 功能: 指示指定的列是否明确不可写入。 196 第9章 JDBC 元数据处理 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 s. public boolean isWritable(int column) 功能: 指示在指定的列上进行写操作是否可以获得成功。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 fals。 t. public boolean isDefinitelyWritable(int column) 功能: 指示在指定的列上进行写操作是否明确可以获得成功。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: 如果是这样,则返回 true;否则返回 false 。 u. public String getColumnClassName(int column) 功能: 如果调用方法 ResultSet.getObject 从列中获取值,则返回构造其实例的 Java 类的完全限定名称。ResultSet.getObject 可能返回此方法所返回的类的子类。 参数: column - 第一列是 1,第二个列是 2,…… 返回值: Java 编程语言中类的完全限定名称,方法 ResultSet.getObject 将使用该名称获取指定列中的值。此名称为用于 自定义映射关系的类名称。 197 第 10 章 JDBC 读写分离 10章 JDBC 读写分离 第 JDBC 读写分离功能是配合数据库读写分离集群使用的,使用读写分离功能需要开启数据库读写分离集群。 JDBC 读写分离主旨是通过 JDBC 驱动实现读写分离,并对应用透明。JDBC 内部直接识别语句类型和事务读写状 态,把读事务中的读语句分发给备机节点执行,以减轻主机的读语句负载,提高整体 DB 集群的处理能力。 • 使用读写分离功能 • 读写分离一些现象分析 10.1 使用读写分离功能 JDBC 默认使用单机方式,如需开启读写分离功能,需指定连接参数 USEDISPATCH 为 true ,同时配置备机地 址与备机端口,以及各节点的名称。配置读写分离的所有参数可在 JDBC 建立/关闭连接看到。 a. 配置读写分离的基本参数 一般情况下,只需以下 5 个参数来控制: # 打开读写分离功能 USEDISPATCH=true # 备机地址 SLAVE_ADD=192.168.8.223,192.168.8.130 # 备机端口 SLAVE_PORT=54321,54321 # 指定各节点的名称, 与主备机地址一一对应 nodeList=node1,node2,node3 # 主机负载率,备机之间轮询平分 HOSTLOADRATE=33 b. 读写分离语句分发策略 读语句分发,分两种情况: (1)单语句事务,这种情况下每条语句都是一个独立的事务,所以读语句分发备机没有问题。 198 第 10 章 JDBC 读写分离 (2)多语句事务,这种情况下,读语句处于事务内,分发需要考虑事务隔离级别,KingbaseES 支持的三 种隔离级别:可重复读 (RP),读已提交 (RC),序列化。严格意义上这三种都不允许读语句分发,因为可 能出现’ 不可重复读’ 或者’ 读不到已提交’ 的内容。但是如果事务内的语句就不分发的话,读写分离就失 去了大半意义,因为无论是应用还是框架,基本上都是用事务控制的,所以 JDBC 提供一个分发策略参 数 TransactionDispatchStrategy 控制。 TransactionDispatchStrategy 可以选择分发策略(性能优先,默认是 2): 1 表示事务内的所有语句都只发主机,完全不分发备机; 2 表示事务内遇到写语句之前的读语句,可以分发备机,遇到写语句之后就只发主机。 c. 读写分离读语句可分发节点选择策略 readListStrategy 可以选择可分发节点选择策略(性能优先,默认是 1): 1 表示所有节点均可分发:只看是不是可用的在线节点,是就可以分发,不考虑备机的数据延迟,最大化 分发,负载效率最好,但可能出现备机数据延迟造成的主备读取数据不一致。属于弱一致性,适用不要求 强一致的应用,比如历史数据分析。 2 表示只发主机同步备机:异步备机只做 HA,读语句可分发到主机和同步备机,最大化读取一致性,但 是无法利用异步备机负载,性能有损耗,属于强一致性,适用要求强一致的应用。 d. 读写分离对事务隔离性的影响 所有节点均可分发 只发主机、同步备机 事务内只发主 满足 RP,不满足 RC 满足 RP,满足 RC 事务内写前分发 都不满足 不满足 RP,满足 RC e. 读写分离对写后读一致性的影响 所有节点均可分发 只发主机、同步备机 事务内 满足 满足 事务间 不满足 满足 f. 读写分离语句失败重发 JDBC 支持切机本意就是指尽量让应用的语句不因为切机造成执行失败,让应用对切机无感知。对于单事 务语句基本都可以重发成功,但并不是所有的语句都可以重发成功。涉及连接会话上下文的以下几种情况 会重发失败: (1)游标:cursor,refcursor 切机后全部丢失,重发不能成功。 (2)事务:切机后连接全部都断掉了,事务回退失败,不能重发。 (3)结果集遍历:和游标类似,重发不能成功。 199 第 10 章 JDBC 读写分离 (4)批量操作:批量操作只能全部重做,但有可能已经有部分数据执行成功,如果重发可能会导致重复 执行,故不能重发。 10.2 读写分离一些现象分析 a. 集群状态正常,socketTimeout 设置大于 0 时,为什么执行时间超长的事务会失败并导致 jdbc 重建连接? sockettimeout 是控制底层 socket 超时返回的最长时间,默认是 0,即没有超时。 如果指定大于 0 的值,意思就是最多等待 sockettimeout 的时间,socket 的 receive 操作就会返回。这主要是用 来防止当 server 掉线时,client 端 socket 的 receive 操作会一直等待。但是这会带来副作用,就是如果一条语句 真的执行很长时间超过了 sockettimeout 的值时,会被认为是超时而中断 receive 返回超时错误。 如果是在读写分离状态下,超时会造成重建连接重发语句,会导致超时语句重试达到最大重发次数才会报错返 回。驱动有检测机器是否掉线的机制,不会出现一直等待的现象,所以无需配置 socketTimeout,使用默认值 0 即可。 b. 主备切换后,备机 rewind,或者备机故障后,备机恢复时为什么备机的连接数是持续上升,而不是一次性全部 建好? 主备切换后,连接不是马上就全部建立起来的,而是应用确实调用到 JDBC 时,JDBC 才会去判断集群是否 切换了,重建连接,重发语句执行。所以连接数的恢复速度和应用操作 JDBC 负荷有关,通常是慢慢建立起 来的,备机的连接会稍滞后于主机连接恢复速度,因为切机重发时,都是只要能找到新的主机就可以重发成功 了,不会等到所有备机重启完成。只有等到下一次发送语句触发备机时,JDBC 才会去检测备机是否已经起来 了,如果未建起才会去重建备机连接。 c. 主机切机后,应用第一次登陆 WEB 慢,JDBC 等待时间分析。 局域网内测试拔网线切机后的过程: 1. 集群的新主机起来可连接后; 2. 应用用户登录 WEB; 3. 使用连接池中已经有的 JDBC 连接 (主机的连接都已经失效,备机的 rewind 之前都还在); 4. 发送 SQL; 5. (I/O Error 20 秒) 收到错误返回; 6. 重建 JDBC 连接 (sleep 5 秒); 7. (在线 0.1 秒返回)+(不在线的需要 10 秒返回)。重建连接完成开始执行登陆 SQL 返回,总计 35 秒左右。 其中 (不在线的需要 10 秒返回) 这个可以通过 connectTimeout 参数控制 connect 超时时间,默认是 10 秒。其 中 (sleep 5 秒) 这个可以通过 RETRYINTERVAL 参数控制重建连接的间隔时间,默认是 5 秒。其中 (I/O Error 20 秒) 这个可以通过 socketTimeout 参数控制 receive 的超时时间,默认是 0,无限等待。 备机的连接不是立刻断掉,而是在一段时间内都还可以使用,等到 rewind 时连接才会全部断掉。 200 第 11 章 JDBC 读写分离最佳实践 11章 JDBC 读写分离最佳实践 第 对于不同场景,可根据实际需要选择不同的读写分离配置,以达到不同的预期效果。 • 读写分离最大性能 • 读写分离(读已提交)最大一致性 • 读写分离(可重复读)最大一致性 读写分离最大性能 11.1 概念 不考虑备机数据延迟造成的主备不一致问题,所有节点均可承担读负载。 适用场景 应用对强一致性不要求,比如历史报表业务;或者应用有自己的处理规避方式,比如影响业务逻辑的关键查询都 放在一个事务内的 DML 语句后面。 配置 1. 前端 KingbaseES 的读写分离 URL: jdbc:kingbase8://192.168.0.100:54321/test?ConfigurePath=jdbc.conf 配置文件 jdbc.conf: USEDISPATCH=true SLAVE_ADD=192.168.0.101,192.168.0.102 SLAVE_PORT=54321,54321 nodeList=node1,node2,node3 HOSTLOADRATE=33 2. 后端 KingbaseES 的读写分离集群 后端采用全异步备机,主库配置为: 201 第 11 章 JDBC 读写分离最佳实践 synchronous_standby_names='' synchronous_commit=off NOTE • 前端配置解释 表 11.1.1: JDBC 的配置项: JDBC 配置集群节点信息 节点地址 一般建议连接串上写主节点 的 地 址, 其 它 备 机 地 址 配 置 SLAVE_ADD 和 SLAVE_PORT 节点名字 nodeList 指定各节点的名称,各 节 点 的 名 称 为./ repmgr cluster show 命令查询出的 Name 字 段。要求开启读写分离时必须配 置此项,不允许为空并要与节点 的地址配置顺序完全一致。各个 节点名称之间用逗号分隔,如: nodeList=node1,node2,node3。 读写分离开启和主机负载 – 打 开 读 写 分 离 功 能: USEDISPATCH=true – 主机负载率,备机之间轮询 平分:HOSTLOADRATE=33 表 11.1.2: JDBC 的配置方式: 连接串配置 只用连接串开启 JDBC 读写分离 jdbc:kingbase8://192.168.0.100: 一主两备 54321/test?USEDISPATCH= true&SLAVE_ADD=192.168. 0.101,192.168.0.102&SLAVE_ PORT=54321,54321&nodeList= node1,node2,node3 连接串 + 配置文件 连接串 + 配置文件开启 JDBC 读 jdbc:kingbase8://192.168.0.100: 写分离一主两备 54321/test?ConfigurePath=jdbc. conf 见续表 202 第 11 章 JDBC 读写分离最佳实践 表 11.1.2 – 续表 jdbc.conf 配置文件: USEDISPATCH=true SLAVE_ADD=192.168.0.101,192.168.0.102 SLAVE_PORT=54321,54321 nodeList=node1,node2,node3 • 后端配置解释 如果’synchronous_standby_names’ 为空,’synchronous_commit’ 设置’on’、’remote_apply’、’remote_write’ 和’local’ 都提供了同样的同步级别:事务提交只等待本地刷写磁盘。 下表以一主两备的三个节点集群为例: sync_state synchronous(repmgr.conf 配置) 全备节点 synchronous_standby_names(数 synchronous_standby_names(数 据 据库配置-old) 库配置-new) all ALL (*) ALL (node_name2,node_name3) quorum ANY 1(*) ANY 为 sync 全 备 节 点 为 1(node_name2,node_name3) quorum 同 步 sync 1 (*) 1 (node_name2,node_name3) async 空 空 节 点 为 sync, 其 余 为 potential 全备节点 为 async 11.2 读写分离(读已提交)最大一致性 概念 需要考虑备机数据延迟造成的主备不一致问题,只有强同步或主节点可承担读负载。 适用场景 应用需要强一致性,比如严格依赖查询数据做后面的逻辑分支处理,一个事务插入,后一个事务马上查询这条数 据,此时就会需要严格一致性。 203 第 11 章 JDBC 读写分离最佳实践 • 强同步节点的定义 首先是主备之间是同步模式,其次备库的同步级别必须是 remote_apply。 • JDBC 对强同步节点的验证方式 select application_name, sync_state from sys_stat_replication 返回的’sync_state’ 必须是’sync’。 配置 1. 前端 KingbaseES 的 JDBC 读写分离 在读写分离最大性能 的基础上,增加一个控制参数“可分发节点选择列表策略”: 指定可分发节点选择列表策略,1 表示所有在线节点均可分发,2 表示只分发主节点和同步备机节点,默认取值 为:’1’。 readListStrategy=2 2. 后端 KingbaseES 的读写分离集群 主库配置: # 1(*) 或者 ALL (*) synchronous_standby_names='1(*)' synchronous_commit=remote_apply 11.3 读写分离(可重复读)最大一致性 概念 一个事务内的两次相同查询需要获得的数据是完全一致的,此时不能分发,只能全部走主机,备机节点此时无法 承担读负载,只用作数据备份,不对外提供服务。 适用场景 应用原来就依赖于严格的 RP 做业务处理。 配置 1. 前端 KingbaseES 的 JDBC 读写分离 在读写分离最大性能 的基础上,增加一个控制参数“可分发节点选择列表策略”: 指定可分发节点选择列表策略,1 表示事务都不分发,2 表示事务中的写语句之前的读语句可以分发,默认取值 为:’2’。 TransactionDispatchStrategy=1 204 第 11 章 JDBC 读写分离最佳实践 2. 后端 KingbaseES 的读写分离集群 主库配置参见读写分离(读已提交)最大一致性 。 205 第 12 章 JDBC 高可用最佳实践 12章 JDBC 高可用最佳实践 第 读写分离集群只连接主节点,备机作为高可用节点使用。 JDBC 支持多主机地址功能,可以利用该功能来实现集群高可用。 以下是主备集群连接高可用的最佳实践配置: 一个三节点的主备集群,服务器地址为:192.168.1.121:54321,192.168.1.122:54321,192.168.1.123:54321。 要在此集群上实现高可用,则使用多主机地址连接 URL 的样例: URL: jdbc:kingbase8://192.168.1.121:54321,192.168.1.122:54321,192.168.1.123:54321/test? targetServerType=master 集群内的服务器可以使用不同的端口,但账号和密码需要保持一致。 集群中的主机地址格式为 IP:PORT,多个地址中间使用”,” 分隔。 使用该 URL 连接主备集群,集群内的节点不管角色发生什么变化,应用都能自动找到主节点进行操作。 URL 中可配置的高可用参数说明: • targetServerType 指定要连接的服务器类型。any 表示不区分主备,任意节点都可连接;master 表示连接主节点; slave 表示连接备节点;preferSlave 表示优选备节点,只要 ip:port 列表有一个备节点,则优先选择 进行连接,除非所有的备机节点都不可连接,才选择连接主节点。默认值为 any。 • loadBalanceHosts 指定是否开启负载均衡模式。如果设置为 false,将按照给定的顺序连接主机;如果设置为 true,则 会从合适的候选集合中随机选择启用的主机。默认值为 false。 • hostRecheckSeconds 指定检查主机状态的周期。JDBC 尝试连接主机后会保存主机状态:连接成功或连接失败。在周期内 可信,超过周期则状态失效。默认值为 10 毫秒。 • connectTimeout 206 第 12 章 JDBC 高可用最佳实践 控制连接超时时间,默认值为 10 秒。如果超过设置的时间没有得到响应,则会自动终止连接,避免 长时间等待。 • fastFailover 指定是否启动快速故障转移,开启后,如果配置了多主机地址,多次建立连接,后续会默认连接第 一次成功连接的地址。此参数不能与 loadBalanceHosts 参数同时开启。默认值为 false。 207 第 13 章 JDBC 示例说明 13章 JDBC 示例说明 第 在所提供的用例中,使用的数据库信息为,用户名:system;密码:manager; 数据库名:test;端口号:54321 • DataSource 示例 • ConnectionPooling 示例 • Statement 示例 • PreparedStatement 示例 • CallableStatement 示例 • ResultSet 示例 • BLOB 示例 • CLOB 示例 • Transaction 示例 • DatabaseMetadata 示例 • 调用存储过程示例 • interval year[(n)] to month 示例 • interval day[(n)] to second[(m)] 示例 您可前往 人大金仓官网 下载 JDBC 测试用例 。 13.1 DataSource 示例 例 13-1. DataSource 的使用 import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; 208 第 13 章 JDBC 示例说明 import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import com.kingbase8.jdbc3.Jdbc3SimpleDataSource; public class testDataSource { public static void main(String[] args) throws NamingException, SQLException { Jdbc3SimpleDataSource ds = new Jdbc3SimpleDataSource(); ds.setServerName("localhost"); ds.setDatabaseName("test"); ds.setUser("system"); ds.setPassword("manager"); ds.setPortNumber(54321); Context ctx = null; try { Hashtable env = new Hashtable(5); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put(Context.PROVIDER_URL, "file:/job/jndi"); ctx = new InitialContext(env); } catch (NamingException ne) { ne.printStackTrace(); } ctx.rebind("DataSource", ds); Context ctx2 = null; try { Hashtable env = new Hashtable(5); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); env.put(Context.PROVIDER_URL, "file:/job/jndi"); ctx2 = new InitialContext(env); 209 第 13 章 JDBC 示例说明 } catch (NamingException ne) { ne.printStackTrace(); } DataSource ds2 = (DataSource) ctx2.lookup("DataSource"); Connection conn = ds2.getConnection(); Statement stmt = conn.createStatement(); stmt.executeUpdate("create table dataSource (id int)"); stmt.executeUpdate("insert into dataSource values (1)"); ResultSet rs = stmt.executeQuery("select * from dataSource"); while(rs.next()) { System.out.println("id:"+ rs.getInt(1)); } stmt.executeUpdate("drop table dataSource"); rs.close(); stmt.close(); conn.close(); } } 13.2 ConnectionPooling 示例 例 13-2. ConnectionPooling 的使用 import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.kingbase8.jdbc3.Jdbc3PoolingDataSource; public class testPooling { public static void main(String[] args) throws SQLException { 210 第 13 章 JDBC 示例说明 Jdbc3PoolingDataSource ds = new Jdbc3PoolingDataSource(); ds.setDataSourceName("A Data Source"); ds.setServerName("localhost"); ds.setDatabaseName("test"); ds.setUser("system"); ds.setPassword("manager"); ds.setMaxConnections(10); ds.setInitialConnections(10); ds.setPortNumber(54321); Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); stmt.executeUpdate("create table pool (id int)"); stmt.executeUpdate("insert into pool values (1)"); ResultSet rs = stmt.executeQuery("select * from pool"); while(rs.next()) { System.out.println("id:"+ rs.getInt(1)); } stmt.executeUpdate("drop table pool"); rs.close(); stmt.close(); conn.close(); ds.close(); } } 13.3 Statement 示例 例 13-3. Statement 的使用 import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; 211 第 13 章 JDBC 示例说明 protected Statement statement = null; protected String create_table = "create table orders(ORDER_ID SERIAL, " + "ISBN int, CUSTOMERID varchar(20))"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testStatement test = new testStatement(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.getGeneratedKeys(); test.close(); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException 212 第 13 章 JDBC 示例说明 { statement.executeUpdate(create_table); } protected void getGeneratedKeys() throws SQLException { int rows = statement.executeUpdate("insert into orders (ISBN," + "CUSTOMERID) VALUES (195123018,'BILLING')" , Statement.RETURN_GENERATED_KEYS); System.out.println("rows:" + rows); ResultSet rs = null; rs = statement.getGeneratedKeys(); boolean b = rs.next(); if (b) { System.out.println(rs.getString(1)); } rs.close(); statement.executeUpdate("delete from orders"); boolean result = statement.execute("insert into orders (ISBN," + "CUSTOMERID) VALUES (195123018,'BILLING')" , Statement.RETURN_GENERATED_KEYS); System.out.println("result:"+result); rs = statement.getGeneratedKeys(); boolean c = rs.next(); if (c) { System.out.println(rs.getString(1)); } rs.close(); statement.executeUpdate("delete from orders"); String keyColumn[] = {"order_id"}; int row = statement.executeUpdate("insert into orders (ISBN," + "CUSTOMERID) VALUES (195123018,'BILLING')", keyColumn); System.out.println("row:"+row); rs = statement.getGeneratedKeys(); boolean d = rs.next(); if(d) { System.out.println(rs.getString(1)); } 213 第 13 章 JDBC 示例说明 rs.close(); statement.executeUpdate("delete from orders"); String keyColumn1[] = {"order_id"}; boolean result1 = statement.execute("insert into orders (ISBN," + "CUSTOMERID) VALUES (195123018,'BILLING')", keyColumn1); System.out.println("result1:"+result1); rs = statement.getGeneratedKeys(); boolean e = rs.next(); if(e) { System.out.println(rs.getString(1)); } rs.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table orders"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 13.4 PreparedStatement 示例 例 13-4. PreparedStatement 的使用 import java.math.BigDecimal; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; 214 第 13 章 JDBC 示例说明 import java.sql.Statement; public class testPreparedStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected enumn[] employee = new enumn[5]; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } public static void main(String[] args) throws SQLException, ClassNotFoundException, InterruptedException { testPreparedStatement test = new testPreparedStatement(); test.initEmployee(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.preparedStatement(); test.getParameterMetaData(); test.close(); } protected void initEmployee() { for(int i = 0; i < employee.length; i++) { employee[i] = new enumn(); employee[i].id = i; employee[i].salary = new BigDecimal("100." + i); } } protected void connection(String url) throws SQLException, InterruptedException { 215 第 13 章 JDBC 示例说明 connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table employees (ID int not null " + "primary key, SALARY numeric(9,5))"); for(int i = 0; i < 5 ; i++) { statement.executeUpdate("insert into employees values (" + i + "," + "100.10" + ")"); } } protected void preparedStatement() throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement( "UPDATE employees SET SALARY = ? WHERE ID = ?"); for(int i = 0; i < employee.length; i++) { preparedStatement.setBigDecimal(1, employee[i].salary); preparedStatement.setInt(2, employee[i].id); preparedStatement.executeUpdate(); } ResultSet rs = statement.executeQuery("select SALARY from employees"); while(rs.next()) { 216 第 13 章 JDBC 示例说明 System.out.println(rs.getBigDecimal(1)); } rs.close(); preparedStatement.close(); } protected void getParameterMetaData() throws SQLException { statement.executeUpdate("delete from employees"); PreparedStatement preparedStatement = connection.prepareStatement( "insert into employees (ID, SALARY) values (?,?)"); ParameterMetaData pmd = preparedStatement.getParameterMetaData(); int parameterCount = pmd.getParameterCount(); System.out.println(parameterCount); preparedStatement.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table employees"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } class enumn { BigDecimal salary; int id; } 13.5 CallableStatement 示例 例 13-5. CallableStatement 的使用 217 第 13 章 JDBC 示例说明 import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import com.kingbase8.jdbc.KbCallableStatement; public class testCallableStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table callable (number int, " + "xm char(20), gz float)"); 218 第 13 章 JDBC 示例说明 for(int i = 0; i < 5 ; i++) { statement.executeUpdate("insert into callable values ("+ i + "," + "'a" + i + "'," + 123.1 + ")"); } } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testCallableStatement test = new testCallableStatement(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.callableStatement(); test.close(); } public void callableStatement() throws SQLException { String sql = "create or replace procedure procName (inout id " + "int, in name char(20),out salary float) as " + "begin " + "select number into id from callable where number " + "= id and xm = name;" + "select gz into salary from callable where number " + "= id and xm = name;" + "end;"; /* String sql = "create or replace function procName (inout id " * + "int, in name char(20),out salary float) as '" * + "begin " * + "select number into id from callable where number " * + "= id and xm = name;" * + "select gz into salary from callable where number " * + "= id and xm = name;" * + "end;' LANGUAGE plpgsql;"; */ statement.execute(sql); CallableStatement cstmt = connection.prepareCall( "{call procName(?,?,?)}"); 219 第 13 章 JDBC 示例说明 cstmt.setInt(1, 2); cstmt.setString(2, "a2"); cstmt.registerOutParameter(1,java.sql.Types.INTEGER); cstmt.registerOutParameter(3, java.sql.Types.REAL); cstmt.execute(); System.out.println(cstmt.getInt(1)); System.out.println(cstmt.getFloat(3)); CallableStatement cstmt2 = connection.prepareCall( "{call procName(?,?,?)}"); cstmt2.registerOutParameter("id",java.sql.Types.INTEGER); cstmt2.registerOutParameter("salary",java.sql.Types.REAL); cstmt2.setInt("id",2); cstmt2.setString("name", "a2"); cstmt2.execute(); System.out.println(cstmt2.getInt("id")); System.out.println(cstmt2.getFloat("salary")); KbCallableStatement cstmt3 = (KbCallableStatement) connection.prepareCall( "{call procName(:id,:name,:salary)}"); cstmt3.registerOutParameterAtName("id",java.sql.Types.INTEGER); cstmt3.registerOutParameterAtName("salary",java.sql.Types.REAL); cstmt3.setIntAtName("id",2); cstmt3.setStringAtName("name", "a2"); cstmt3.execute(); System.out.println(cstmt.getInt(1)); System.out.println(cstmt.getFloat(3)); } protected void close() throws SQLException { statement.executeUpdate("drop table callable"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 220 第 13 章 JDBC 示例说明 例 13-6. oracle 兼容模式下,refcursor 为 OUT 参数和 RETURN 参数时,CallableStatement 的使用 import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; public class testCallableStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/TEST"; protected Connection connection = null; protected Statement statement = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table testrs (id integer primary " + "key)"); for(int i = 0; i < 5 ; i++) 221 第 13 章 JDBC 示例说明 { statement.executeUpdate("insert into testrs values (" + i + ")"); } } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testCallableStatement test = new testCallableStatement(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.callableStatement(); test.close(); } public void callableStatement() throws SQLException { statement.execute("CREATE OR REPLACE INTERNAL FUNCTION " + "testssys_getRefcursor() RETURNS refcursor AS '" + "declare v_resset refcursor; " + "begin " + "open v_resset for select id from testrs order by id; " + "return v_resset; " + "end;' LANGUAGE plsql;"); statement.execute("create or replace procedure " + "testssys_demo(v_temp out refcursor) as \n" + "begin \n" + "open v_temp for select id from testrs; \n" + "end; "); connection.setAutoCommit(false); CallableStatement call = connection.prepareCall( "{ ? = call testssys_getRefcursor() }"); call.registerOutParameter(1, Types.REF_CURSOR); call.execute(); ResultSet rs = (ResultSet) call.getObject(1); System.out.println("testssys_getRefcursor:"); while(rs.next()) { System.out.println(rs.getInt(1)); } 222 第 13 章 JDBC 示例说明 CallableStatement call2 = connection.prepareCall( "{call testssys_demo (?)}"); call2.registerOutParameter(1, Types.REF_CURSOR); call2.execute(); ResultSet rs2 = (ResultSet) call2.getObject(1); System.out.println("testssys_demo:"); while(rs2.next()){ System.out.println(rs2.getInt(1)); } connection.commit(); connection.setAutoCommit(true); } protected void close() throws SQLException { statement.executeUpdate("drop table testrs"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 例 13-7. PG 兼容模式下,refcursor 为 OUT 参数和 RETURN 参数时,CallableStatement 的使用 import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; public class testCallableStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; 223 第 13 章 JDBC 示例说明 protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table testrs (id integer primary " + "key)"); for(int i = 0; i < 5 ; i++) { statement.executeUpdate("insert into testrs values (" + i + ")"); } } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testCallableStatement test = new testCallableStatement(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.callableStatement(); test.close(); } 224 第 13 章 JDBC 示例说明 public void callableStatement() throws SQLException { statement.execute("CREATE OR REPLACE FUNCTION " + "testssys_getRefcursor() RETURNS refcursor AS '" + "declare v_resset refcursor; " + "begin " + "open v_resset for select id from testrs order by id; " + "return v_resset; " + "end;' LANGUAGE plpgsql;"); statement.execute("create or replace procedure " + "testssys_demo(v_temp inout refcursor) as '\n" + "begin \n" + "open v_temp for select id from testrs; \n" + "end;' LANGUAGE plpgsql;"); connection.setAutoCommit(false); CallableStatement call = connection.prepareCall( "{ ? = call testssys_getRefcursor() }"); call.registerOutParameter(1, Types.REF_CURSOR); call.execute(); ResultSet rs = (ResultSet) call.getObject(1); System.out.println("testssys_getRefcursor:"); while(rs.next()) { System.out.println(rs.getInt(1)); } CallableStatement call2 = connection.prepareCall( "call testssys_demo (?)"); call2.setObject(1, null); call2.registerOutParameter(1, Types.REF_CURSOR); call2.execute(); ResultSet rs2 = (ResultSet) call2.getObject(1); System.out.println("testssys_demo:"); while(rs2.next()){ System.out.println(rs2.getInt(1)); } connection.commit(); connection.setAutoCommit(true); } protected void close() throws SQLException { statement.executeUpdate("drop table testrs"); if(statement != null) { statement.close(); 225 第 13 章 JDBC 示例说明 } if(connection != null) { connection.close(); } } } 例 13-8. oracle 兼容模式下,存储过程返回多结果集时,CallableStatement 的使用 import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; public class testCallableStatement { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/TEST"; protected Connection connection = null; protected Statement statement = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException 226 第 13 章 JDBC 示例说明 { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table testrs (id integer primary " + "key)"); for(int i = 0; i < 5 ; i++) { statement.executeUpdate("insert into testrs values (" + i + ")"); } } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testCallableStatement test = new testCallableStatement(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.callableStatement(); test.close(); } public void callableStatement() throws SQLException { statement.execute("create or replace procedure " + "testssys_demo(v_temp out refcursor) as \n" + "begin \n" + "select * from testrs;" + "open v_temp for select id from testrs; \n" + "end; "); connection.setAutoCommit(false); CallableStatement call2 = connection.prepareCall( "{call testssys_demo (?)}"); call2.registerOutParameter(1, Types.REF_CURSOR); call2.execute(); ResultSet rs2 = (ResultSet) call2.getObject(1); System.out.println("testssys_demo:"); while(rs2.next()){ 227 第 13 章 JDBC 示例说明 System.out.println(rs2.getInt(1)); } rs2 = call2.getResultSet(); while(rs2.next()){ System.out.println(rs2.getInt(1)); } connection.commit(); connection.setAutoCommit(true); } protected void close() throws SQLException { statement.executeUpdate("drop table testrs"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 13.6 ResultSet 示例 例 13-9. ResultSet 的使用 import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; public class testResultSet { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; 228 第 13 章 JDBC 示例说明 protected Statement statement = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table table1(id int primary key," + "name char(10))"); statement.executeUpdate("insert into table1 values (1,'KingbaseES')"); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testResultSet test = new testResultSet(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.resultSet(); test.updataResultSet(); test.close(); } 229 第 13 章 JDBC 示例说明 protected void resultSet() throws SQLException { ResultSet rs = statement.executeQuery("select * from table1"); while(rs.next()) { System.out.println(rs.getInt(1)); } ResultSetMetaData rsmd = rs.getMetaData(); System.out.println(rsmd.getColumnTypeName(1)); rs.close(); } protected void updataResultSet() throws SQLException { Statement stmt = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("select * from table1"); rs.next(); System.out.println("update before: " + rs.getInt(1)); rs.updateInt(1, 21); rs.updateRow(); System.out.println("update after: " + rs.getInt(1)); rs.close(); stmt.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table table1"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 230 第 13 章 JDBC 示例说明 13.7 BLOB 示例 例 13-10. oracle 兼容模式下,BLOB 的使用 import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testBlob { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected String source = "Welcome to Kingbase!"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException 231 第 13 章 JDBC 示例说明 { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table blob_table (col1 Blob, " + "col2 Blob, col3 Blob)"); } protected void insertBlob() throws SQLException { PreparedStatement pstmt = connection.prepareStatement( "insert into blob_table values (?,?,?)"); InputStream read = new ByteArrayInputStream(source.getBytes()); InputStream read1 = new ByteArrayInputStream(source.getBytes()); InputStream read2 = new ByteArrayInputStream(source.getBytes()); pstmt.setBlob(1, read); pstmt.setBlob(2, read1); pstmt.setBlob(3, read2); pstmt.executeUpdate(); pstmt.close(); } protected void queryBlob() throws SQLException, IOException { String sql_select = "select * from blob_table"; ResultSet resultSet = statement.executeQuery(sql_select); int count = 1; while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); String blob1 = new String(resultSet.getBytes(1)); String blob2 = new String(resultSet.getBytes(2)); String blob3 = new String(resultSet.getBytes(3)); System.out.println("blob1:" + blob1); System.out.println("blob2:" + blob2); System.out.println("blob3:" + blob3); count++; } resultSet.close(); 232 第 13 章 JDBC 示例说明 count = 1; resultSet = statement.executeQuery(sql_select); while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); for(int i = 0; i < 3; i++) { Blob blob = resultSet.getBlob(i+1); InputStream input = blob.getBinaryStream(); StringWriter sWriter = new StringWriter(); int j = -1; while((j = input.read()) != -1) { sWriter.write(j); } String finalBlob = new String(sWriter.getBuffer()); System.out.println(finalBlob); } count++; } resultSet.close(); } protected void updateBlob() throws SQLException, IOException { String sql_select = "select * from blob_table for update"; ResultSet resultSet = statement.executeQuery(sql_select); if(resultSet.next()) { Blob blob = resultSet.getBlob(1); OutputStream output = blob.setBinaryStream(blob.length() + 1); String temp = "Welcome to Kingbase!"; byte[] tempByte = temp.getBytes(); output.write(tempByte); output.close(); blob = resultSet.getBlob(2); temp = "Hello, Kingbase!"; 233 第 13 章 JDBC 示例说明 blob.setBytes(blob.length() + 1, temp.getBytes()); resultSet = statement.executeQuery(sql_select); if(resultSet.next()) { System.out.println(" 更新后的记录"); System.out.println(new String(resultSet.getBytes(1))); System.out.println(new String(resultSet.getBytes(2))); System.out.println(new String(resultSet.getBytes(3))); } } resultSet.close(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException, IOException { testBlob test = new testBlob(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.insertBlob(); test.queryBlob(); test.updateBlob(); test.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table blob_table"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 例 13-11 PG 兼容模式下,BLOB 的使用 import java.io.ByteArrayInputStream; import java.io.IOException; 234 第 13 章 JDBC 示例说明 import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testBlob { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected String source = "Welcome to Kingbase!"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } connection.setAutoCommit(false); } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException 235 第 13 章 JDBC 示例说明 { statement.executeUpdate("create table blob_table (col1 oid, " + "col2 oid, col3 oid)"); } protected void insertBlob() throws SQLException { PreparedStatement pstmt = connection.prepareStatement( "insert into blob_table values (?,?,?)"); InputStream read = new ByteArrayInputStream(source.getBytes()); InputStream read1 = new ByteArrayInputStream(source.getBytes()); InputStream read2 = new ByteArrayInputStream(source.getBytes()); pstmt.setBlob(1, read); pstmt.setBlob(2, read1); pstmt.setBlob(3, read2); pstmt.executeUpdate(); pstmt.close(); } protected void queryBlob() throws SQLException, IOException { String sql_select = "select * from blob_table"; ResultSet resultSet = statement.executeQuery(sql_select); int count = 1; while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); Blob blob1 = resultSet.getBlob(1); Blob blob2 = resultSet.getBlob(2); Blob blob3 = resultSet.getBlob(3); System.out.println("blob1:" + new String(blob1.getBytes(1, (int) blob1.length()))); System.out.println("blob2:" + new String(blob2.getBytes(1, (int) blob2.length()))); System.out.println("blob3:" + new String(blob3.getBytes(1, (int) blob3.length()))); count++; } resultSet.close(); count = 1; resultSet = statement.executeQuery(sql_select); while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); 236 第 13 章 JDBC 示例说明 for(int i = 0; i < 3; i++) { Blob blob = resultSet.getBlob(i+1); InputStream input = blob.getBinaryStream(); StringWriter sWriter = new StringWriter(); int j = -1; while((j = input.read()) != -1) { sWriter.write(j); } String finalBlob = new String(sWriter.getBuffer()); System.out.println(finalBlob); } count++; } resultSet.close(); } protected void updateBlob() throws SQLException, IOException { String sql_select = "select * from blob_table for update"; ResultSet resultSet = statement.executeQuery(sql_select); if(resultSet.next()) { Blob blob = resultSet.getBlob(1); OutputStream output = blob.setBinaryStream(blob.length() + 1); String temp = "Welcome to Kingbase!"; byte[] tempByte = temp.getBytes(); output.write(tempByte); output.close(); blob = resultSet.getBlob(2); temp = "Hello, Kingbase!"; blob.setBytes(blob.length() + 1, temp.getBytes()); resultSet = statement.executeQuery(sql_select); if(resultSet.next()) { System.out.println(" 更新后的记录"); System.out.println(new String(resultSet.getBlob(1).getBytes(1, (int) resultSet.getBlob(1).length()))); System.out.println(new String(resultSet.getBlob(2).getBytes(1, 237 第 13 章 JDBC 示例说明 (int) resultSet.getBlob(2).length()))); System.out.println(new String(resultSet.getBlob(3).getBytes(1, (int) resultSet.getBlob(3).length()))); } } resultSet.close(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException, IOException { testBlob test = new testBlob(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.insertBlob(); test.queryBlob(); test.updateBlob(); test.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table blob_table"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 13.8 CLOB 示例 例 13-12. oracle 兼容模式下 CLOB 的使用 238 第 13 章 JDBC 示例说明 import java.io.IOException; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.sql.Clob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testClob { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected String source = "Welcome to Kingbase!"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } 239 第 13 章 JDBC 示例说明 protected void table() throws SQLException { statement.executeUpdate("create table clob_table (col1 Clob, col2 " + "Clob, col3 Clob)"); } protected void insertClob() throws SQLException { PreparedStatement pstmt = connection.prepareStatement( "insert into clob_table values (?,?,?)"); StringReader reader = new StringReader(source); StringReader reader1 = new StringReader(source); StringReader reader2 = new StringReader(source); pstmt.setClob(1, reader); pstmt.setClob(2, reader1); pstmt.setClob(3, reader2); pstmt.executeUpdate(); pstmt.close(); } protected void queryClob() throws SQLException, IOException { String sql_select = "select * from clob_table"; ResultSet resultSet = statement.executeQuery(sql_select); int count = 1; while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); String clob1 = resultSet.getString(1); String clob2 = resultSet.getString(2); String clob3 = resultSet.getString(3); System.out.println("clob1:" + clob1); System.out.println("clob2:" + clob2); System.out.println("clob3:" + clob3); count++; } resultSet.close(); count = 1; resultSet = statement.executeQuery(sql_select); while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); 240 第 13 章 JDBC 示例说明 for(int i = 0; i < 3; i++) { Clob clob = resultSet.getClob(i+1); Reader reader = clob.getCharacterStream(); StringWriter sWriter = new StringWriter(); int j = -1; while((j = reader.read()) != -1) { sWriter.write(j); } String finalClob = new String(sWriter.getBuffer()); System.out.println(finalClob); } count++; } resultSet.close(); } protected void updateClob() throws SQLException, IOException { String sql_select = "select * from clob_table for update"; ResultSet resultSet = statement.executeQuery(sql_select); PreparedStatement pstmt = connection.prepareStatement( "update clob_table set col1=?,col2=?,col3=?"); if(resultSet.next()) { Clob clob = resultSet.getClob(1); String temp = "Test has sucessful"; System.out.println(resultSet.getString(1).length()); OutputStream os = clob.setAsciiStream(clob.length() + 1); byte[] tempByte = temp.getBytes(); os.write(tempByte); os.close(); pstmt.setClob(1, clob); clob = resultSet.getClob(2); 241 第 13 章 JDBC 示例说明 Writer writer = clob.setCharacterStream(clob.length() + 1); temp = "Welcome to Kingbase!"; writer.write(temp);writer.write(temp); writer.close(); pstmt.setClob(2, clob); clob = resultSet.getClob(3); temp = "Hello, Kingbase!"; clob.setString(clob.length() + 1, temp); } resultSet = statement.executeQuery(sql_select); if(resultSet.next()) { System.out.println(" 更新后的记录"); System.out.println(resultSet.getString(1)); System.out.println(resultSet.getString(2)); System.out.println(resultSet.getString(3)); } resultSet.close(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException, IOException { testClob test = new testClob(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.insertClob(); test.queryClob(); test.updateClob(); test.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table clob_table"); if(statement != null) { statement.close(); } if(connection != null) 242 第 13 章 JDBC 示例说明 { connection.close(); } } } 例 13-13. PG 兼容模式下 CLOB 的使用 import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringWriter; import java.sql.Clob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testClob { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected String source = "Welcome to Kingbase!"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); 243 第 13 章 JDBC 示例说明 } connection.setAutoCommit(false); } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table clob_table (col1 oid, col2 " + "oid, col3 oid)"); } protected void insertClob() throws SQLException { PreparedStatement pstmt = connection.prepareStatement( "insert into clob_table values (?,?,?)"); InputStream read = new ByteArrayInputStream(source.getBytes()); InputStream read1 = new ByteArrayInputStream(source.getBytes()); InputStream read2 = new ByteArrayInputStream(source.getBytes()); pstmt.setBlob(1, read); pstmt.setBlob(2, read1); pstmt.setBlob(3, read2); pstmt.executeUpdate(); pstmt.close(); } protected void queryClob() throws SQLException, IOException { String sql_select = "select * from clob_table"; ResultSet resultSet = statement.executeQuery(sql_select); int count = 1; while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); Clob clob1 = resultSet.getClob(1); Clob clob2 = resultSet.getClob(2); Clob clob3 = resultSet.getClob(3); System.out.println("clob1:" + clob1.getSubString(1, (int) clob1.length())); System.out.println("clob2:" + clob2.getSubString(1, (int) 244 第 13 章 JDBC 示例说明 clob2.length())); System.out.println("clob3:" + clob3.getSubString(1, (int) clob3.length())); count++; } resultSet.close(); count = 1; resultSet = statement.executeQuery(sql_select); while(resultSet.next()) { System.out.println(" 第" + count + " 条记录"); for(int i = 0; i < 3; i++) { Clob clob = resultSet.getClob(i+1); Reader reader = clob.getCharacterStream(); StringWriter sWriter = new StringWriter(); int j = -1; while((j = reader.read()) != -1) { sWriter.write(j); } String finalClob = new String(sWriter.getBuffer()); System.out.println(finalClob); } count++; } resultSet.close(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException, IOException { testClob test = new testClob(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.insertClob(); test.queryClob(); test.close(); 245 第 13 章 JDBC 示例说明 } protected void close() throws SQLException { statement.executeUpdate("drop table clob_table"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 13.9 Transaction 示例 例 13-14. Transaction 的使用 import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Savepoint; import java.sql.Statement; public class testTransaction { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected Statement statement = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); 246 第 13 章 JDBC 示例说明 if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } protected void table() throws SQLException { statement.executeUpdate("create table transaction (number int)"); } protected void transactionTest() throws SQLException { connection.setAutoCommit(false); Statement stmt = connection.createStatement(); Savepoint svpt2 = connection.setSavepoint("SAVEPOINT_2"); int row1 = stmt.executeUpdate( "INSERT INTO transaction (number) VALUES (1)"); System.out.println(row1); Savepoint svpt1 = connection.setSavepoint("SAVEPOINT_1"); int row2 = stmt.executeUpdate( "INSERT INTO transaction (number) VALUES (2)"); System.out.println(row2); connection.rollback(svpt1); connection.rollback(svpt2); connection.commit(); ResultSet rs = stmt.executeQuery("select * from transaction"); while(rs.next()) { System.out.println(rs.getInt(1)); 247 第 13 章 JDBC 示例说明 } rs.close(); stmt.close(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testTransaction test = new testTransaction(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.transactionTest(); test.close(); } protected void close() throws SQLException { statement.executeUpdate("drop table transaction"); connection.commit(); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 例 13-15. autosave 的使用 import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class testRollbackLevel { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/" + "test?autosave=always"; 248 第 13 章 JDBC 示例说明 protected Connection connection = null; protected Statement statement = null; protected String create_table = "create table orders(id int)"; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { System.out.println("connection fail!"); } } protected void statement() throws SQLException { statement = connection.createStatement(); } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testRollbackLevel test = new testRollbackLevel(); test.Driver(); test.connection(Url); test.statement(); test.table(); test.testLevel(); test.close(); } protected void table() throws SQLException { statement.executeUpdate(create_table); } 249 第 13 章 JDBC 示例说明 protected void testLevel() throws SQLException { connection.setAutoCommit(false); try { statement.execute("insert into orders values(1)"); } catch(SQLException e) { } try { statement.execute("insert into orders values(a)"); } catch(SQLException e) { } try { statement.execute("insert into orders values(3)"); } catch(SQLException e) { } connection.commit(); connection.setAutoCommit(true); ResultSet rs = statement.executeQuery("select * from orders"); while(rs.next()) { System.out.println(rs.getInt(1)); } rs.close(); } protected void close() throws SQLException 250 第 13 章 JDBC 示例说明 { statement.executeUpdate("drop table orders"); if(statement != null) { statement.close(); } if(connection != null) { connection.close(); } } } 13.10 DatabaseMetadata 示例 例 13-16. DatabaseMetadata 的使用 import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.SQLException; public class testDatabaseMetadata { protected String Driver = "com.kingbase8.Driver"; protected static String Url = "jdbc:kingbase8://localhost:54321/test"; protected Connection connection = null; protected void Driver() throws ClassNotFoundException { Class.forName(Driver); } protected void connection(String url) throws SQLException, InterruptedException { connection = DriverManager.getConnection(url, "system", "manager"); if(connection != null) { System.out.println("connection sucessful!"); } else { 251 第 13 章 JDBC 示例说明 System.out.println("connection fail!"); } } public static void main(String[] args) throws ClassNotFoundException, SQLException, InterruptedException { testDatabaseMetadata test = new testDatabaseMetadata(); test.Driver(); test.connection(Url); test.metaDate(); test.close(); } protected void metaDate() throws SQLException { DatabaseMetaData metaDate = connection.getMetaData(); Connection connection = metaDate.getConnection(); int DatabaseMajorVersion = metaDate.getDatabaseMajorVersion(); int JDBCMajorVersion = metaDate.getJDBCMajorVersion(); System.out.println(JDBCMajorVersion); } protected void close() throws SQLException { if(connection != null) { connection.close(); } } } 13.11 调用存储过程示例 调用存储过程,使用 CallableStatement 接口。 /** * 无返回值 call 调用格式的函数调用 * 252 第 13 章 JDBC 示例说明 * @throws SQLException SQL 异常 */ @Test public void testProcParamNames() throws SQLException { CallableStatement call = connection.prepareCall( "call proc1(1,?,?)"); call.setDouble("b", 2); call.registerOutParameter("c", Types.VARCHAR); call.execute(); String col3 = call.getString("c"); assertEquals("a", col3); call = connection.prepareCall( "{call proc1(1,?,?)}"); call.setDouble("b", 2); call.registerOutParameter("c", Types.VARCHAR); call.execute(); col3 = call.getString("c"); assertEquals("a", col3); } @Test public void testProcParamNames2() throws SQLException { CallableStatement call = connection.prepareCall( "call proc1(?,1,?)"); call.setInt(1, 2); call.registerOutParameter(2, Types.VARCHAR); call.execute(); String col3 = call.getString(2); assertEquals("a", col3); call = connection.prepareCall( "{call proc1(?,1,?)}"); call.setInt(1, 2); call.registerOutParameter(2, Types.VARCHAR); call.execute(); col3 = call.getString(2); assertEquals("a", col3); } @Test public void testFuncParamNamesWithReturnBindAtName() throws SQLException { CallableStatement call = connection.prepareCall( "{? = call func1(?,1,?)}"); call.registerOutParameter("returnValue", Types.DOUBLE); call.setString("a", "1"); call.registerOutParameter("c", Types.VARCHAR); call.execute(); 253 第 13 章 JDBC 示例说明 String col3 = call.getString("c"); assertEquals("a", col3); } @Test public void testFuncParamNamesWithReturnBindAtIndex() throws SQLException { CallableStatement call = connection.prepareCall( "{? = call func1(?,1,?)}"); call.registerOutParameter(1, Types.DOUBLE); call.setString(2, "1"); call.registerOutParameter(3, Types.VARCHAR); call.execute(); String col3 = call.getString(3); assertEquals("a", col3); } 13.12 interval year[(n)] to month 示例 例 13-17. 该数据类型只在 Oracle 兼容模式下可用 import com.kingbase8.KBProperty; import com.kingbase8.test.TestUtils; import com.kingbase8.test.jdbc2.BaseTest4.BinMode; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.sql.*; import java.util.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @RunWith(Parameterized.class) public class OracleIntervalTypeTest { private Connection con; private BinMode binaryMode; public OracleIntervalTypeTest(BinMode binaryMode) { setBinaryMode(binaryMode); 254 第 13 章 JDBC 示例说明 } @Parameterized.Parameters(name = "binary = {0}") public static Iterable data() { Collection ids = new ArrayList(); for (BinMode binaryMode : BinMode.values()) { ids.add(new Object[]{binaryMode}); } return ids; } protected void updateProperties(Properties props) { if (binaryMode == BinMode.FORCE) { // set force binary mode transfer forceBinary(props); } else { // set force text mode transfer KBProperty.BINARY_TRANSFER.set(props, false); } } protected void forceBinary(Properties props) { KBProperty.PREPARE_THRESHOLD.set(props, -1); } public final void setBinaryMode(BinMode binaryMode) { this.binaryMode = binaryMode; } @Before public void setUp() throws Exception { Properties props = new Properties(); updateProperties(props); con = TestUtils.openDB_(props); TestUtils.createTable_(con, "tyminterval1", "t1 interval year to month"); } @After public void tearDown() throws Exception { TestUtils.dropTable_(con, "tyminterval1"); TestUtils.closeDB_(con); } 255 第 13 章 JDBC 示例说明 @Test public void testYM() throws SQLException { Statement stmt = con.createStatement(); stmt.execute("SET intervalstyle to sql_standard"); PreparedStatement ps = con.prepareStatement("insert into tyminterval1 values(?)"); ps.setObject(1, "12-1"); ps.execute(); ps.setString(1, "+20-8"); ps.execute(); ps.setObject(1, "-12-1"); ps.execute(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from tyminterval1"); ResultSetMetaData rsmd = rs.getMetaData(); assertEquals(rsmd.getColumnType(1), Types.OTHER); assertEquals(rsmd.getColumnTypeName(1), "yminterval"); assertEquals(rsmd.getColumnClassName(1), "com.kingbase8.jdbc.YMInterval"); assertEquals(rsmd.getColumnLabel(1), "t1"); assertEquals(rsmd.getColumnName(1), "t1"); assertEquals(rsmd.getColumnDisplaySize(1), 5); assertEquals(rsmd.getPrecision(1), 2); assertEquals(rsmd.getScale(1), 0); assertTrue(rs.next()); assertEquals("12-1", rs.getString(1)); assertEquals("12-1", rs.getObject(1).toString()); assertEquals("class com.kingbase8.jdbc.YMInterval", rs.getObject(1).getClass().toString()); assertTrue(rs.next()); assertEquals("20-8", rs.getString(1)); assertEquals("20-8", rs.getObject(1).toString()); assertTrue(rs.next()); assertEquals("-12-1", rs.getString(1)); assertEquals("-12-1", rs.getObject(1).toString()); rs.close(); ps.close(); st.close(); stmt.close(); } } 13.13 interval day[(n)] to second[(m)] 示例 例 13-18. 该数据类型只在 Oracle 兼容模式下可用 256 第 13 章 JDBC 示例说明 import com.kingbase8.KBProperty; import com.kingbase8.test.TestUtils; import com.kingbase8.test.jdbc2.BaseTest4.BinMode; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.sql.*; import java.util.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @RunWith(Parameterized.class) public class OracleIntervalTypeTest { private Connection con; private BinMode binaryMode; public OracleIntervalTypeTest(BinMode binaryMode) { setBinaryMode(binaryMode); } @Parameterized.Parameters(name = "binary = {0}") public static Iterable data() { Collection ids = new ArrayList(); for (BinMode binaryMode : BinMode.values()) { ids.add(new Object[]{binaryMode}); } return ids; } protected void updateProperties(Properties props) { if (binaryMode == BinMode.FORCE) { // set force binary mode transfer forceBinary(props); } else { // set force text mode transfer KBProperty.BINARY_TRANSFER.set(props, false); } } protected void forceBinary(Properties props) { 257 第 13 章 JDBC 示例说明 KBProperty.PREPARE_THRESHOLD.set(props, -1); } public final void setBinaryMode(BinMode binaryMode) { this.binaryMode = binaryMode; } @Before public void setUp() throws Exception { Properties props = new Properties(); updateProperties(props); con = TestUtils.openDB_(props); TestUtils.createTable_(con, "tyminterval3", "t1 interval day to second"); } @After public void tearDown() throws Exception { TestUtils.dropTable_(con, "tyminterval3"); TestUtils.closeDB_(con); } @Test public void testDS() throws SQLException { Statement stmt = con.createStatement(); stmt.execute("SET intervalstyle to sql_standard"); PreparedStatement ps = con.prepareStatement("insert into tyminterval3 values(?)"); ps.setObject(1, "12 12:12:12.111111"); ps.execute(); ps.setString(1, "-12 12:12:12.111111"); ps.execute(); ps.setObject(1, "12 12:12:12.111111"); ps.execute(); Statement st = con.createStatement(); ResultSet rs = st.executeQuery("select * from tyminterval3"); ResultSetMetaData rsmd = rs.getMetaData(); assertEquals(rsmd.getColumnType(1), Types.OTHER); assertEquals(rsmd.getColumnTypeName(1), "dsinterval"); assertEquals(rsmd.getColumnClassName(1), "com.kingbase8.jdbc.DSInterval"); assertEquals(rsmd.getColumnLabel(1), "t1"); assertEquals(rsmd.getColumnName(1), "t1"); assertEquals(rsmd.getColumnDisplaySize(1), 11); 258 第 13 章 JDBC 示例说明 assertEquals(rsmd.getPrecision(1), 2); assertEquals(rsmd.getScale(1), 6); assertTrue(rs.next()); assertEquals("12 12:12:12.111111", rs.getString(1)); assertEquals("12 12:12:12.111111", rs.getObject(1).toString()); assertEquals("class com.kingbase8.jdbc.DSInterval", rs.getObject(1).getClass().toString()); assertTrue(rs.next()); assertEquals("-12 12:12:12.111111", rs.getString(1)); assertEquals("-12 12:12:12.111111", rs.getObject(1).toString()); assertTrue(rs.next()); assertEquals("12 12:12:12.111111", rs.getString(1)); assertEquals("12 12:12:12.111111", rs.getObject(1).toString()); rs.close(); ps.close(); st.close(); stmt.close(); } } 13.14 RowId 示例 例 13-19 RowId 的使用示例 public void testRowId() throws SQLException { Properties properties = new Properties(); properties.setProperty("rowidType", "rowid"); Connection conn = TestUtils.openDB_(properties); Statement statement = conn.createStatement(); String type = "tid"; if (isDatabaseSupportRowid()) { statement.execute("set default_with_rowid=on;"); type = "rowid"; } ResultSet resultSet3 = statement.executeQuery("select rowid,1 from testrowidfrom"); resultSet3.next(); PreparedStatement preparedStatement = conn.prepareStatement("insert into testrowid values(?,?)"); RowId rowId = resultSet3.getRowId(1); preparedStatement.setRowId(1, rowId); preparedStatement.setInt(2, resultSet3.getInt(2)); preparedStatement.execute(); DatabaseMetaData databaseMetaData = conn.getMetaData(); if (isDatabaseSupportRowid()) { 259 第 13 章 JDBC 示例说明 JunitUtils.astEqualsT(RowIdLifetime.ROWID_VALID_FOREVER, databaseMetaData.getRowIdLifetime()); } else { JunitUtils.astEqualsT(RowIdLifetime.ROWID_VALID_TRANSACTION, databaseMetaData.getRowIdLifetime()); } ResultSet rs2 = databaseMetaData.getColumns(null, null, "testrowid", "%"); rs2.next(); JunitUtils.astEqualsT("t1", rs2.getString(4)); JunitUtils.astEqualsT(Types.ROWID, rs2.getInt(5)); JunitUtils.astEqualsT(type, rs2.getString(6)); ResultSet resultSet = statement.executeQuery("select * from testrowid"); ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); JunitUtils.astEqualsT("t1", resultSetMetaData.getColumnLabel(1)); JunitUtils.astEqualsT(Types.ROWID, resultSetMetaData.getColumnType(1)); JunitUtils.astEqualsT(type, resultSetMetaData.getColumnTypeName(1)); while(resultSet.next()) { JunitUtils.astEqualsT(com.kingbase8.jdbc.KbRowId.class, resultSet.getObject(1).getClass()); JunitUtils.astEqualsT(rowId.toString(), resultSet.getRowId(1).toString()); //#if mvn.project.property.kingbase8.jdbc.spec >= "JDBC4.1" JunitUtils.astEqualsT(rowId.toString(), resultSet.getObject(1, RowId.class).toString()); //#endif JunitUtils.astEqualsT(Arrays.toString(rowId.getBytes()), Arrays.toString(resultSet.getRowId(1). getBytes())); JunitUtils.astNotEqualsT(rowId.hashCode(), resultSet.getRowId(1).hashCode()); if (isDatabaseSupportRowid()) { JunitUtils.astTrueT(resultSet.getRowId(1).equals(rowId)); } else { JunitUtils.astFalseT(resultSet.getRowId(1).equals(rowId)); } } conn.close(); } 260 第 14 章 在应用服务器中配置 JDBC 14章 在应用服务器中配置 JDBC 第 • WebSphere5.1 • Weblogic7.0 • Tomcat 14.1 WebSphere5.1 使用 IBM 的 WebSphere5.1 应用服务器,需要配置其 JNDI 和连接池,可通过其产品提供的” 管理控制 台” 工具,先配置 KingbaseES ClassPath 环境,然后配置 JDBC 提供程序环境 JNDI, 最后定制连接池定制属 性,由于与其他服务器不同之处,WebSphere5.1 需要 JDBC 提供 javax.sql.ConnectionPoolDataSource 的实现, 而不是 javax.sql.DataSource 的实现,KingbaseES JDBC 对 javax.sql.ConnectionPoolDataSource 的实现的完整 类路径名称为 com.kingbase8.jdbc3.Jdbc3ConnectionPool,故只需把该实现提供给 WebSphere 即可,另外在定制 com.kingbase8.jdbc3.Jdbc3ConnectionPool 的连接属性时,连接属性的名字大小写敏感(连接属性包括 serverName 、user 、password 、databaseName、portNumber ,其中 serverName 表示数据库服务器的 IP 地址,user 表示登陆 名,password 表示登陆密码,databaseName 表示数据库实例名,portNumber 表示数据库服务器监听的端口号), 具体配置详细信息如下: 第一步:配置 WebSphere 变量,可通过” 管理控制台” 管理界面中的〈环境-> 管理 WebSphere 变量〉路径配置 KingbaseES JDBC 的 ClassPath 环境变量。 第二步:配置 JDBC 提供程序,可通过” 管理控制台” 管理界面中的〈资源->JDBC 提供程序〉配置 KingbaseES 数据库连接 JNDI。 第三步:配置 JDBC 提供程序,可通过” 管理控制台” 管理界面中的 < 资源->JDBC 提供程序-> 数据源-> 定制 属性 > 配置 KingbaseES 数据库连接属性。 配置完成且测试数据库连接成功以后,可在 WebSphere 的安装目录下可找到 resources.xml,在其中可发现如下 的配置文字字段: ${KingBaseJDBCClassPath}/kingbase8jdbc.jar 第四步:应用程序中引用,编程方法如下: 例 14-1. 使用 WebSphere 建立连接 DataSource ds = (DataSource)ctx.lookup("KingBaseDS"); Connection con = ds.getConnection(); Statement stmt = con.createStatement(); 262 第 14 章 在应用服务器中配置 JDBC ResultSet rs = stmt.executeQuery("SELECT ID,NAME FROM T_USERNAME"); while (rs.next()) { out.println(rs.getInt(1) + " " + rs.getString(2) + "
"); } rs.close(); stmt.close(); con.close(); 14.2 Weblogic7.0 使用第三方的应用服务器,需要配置其连接池和 JNDI ,在 Weblogic 中,可通过 Weblogic 提供的控制台先配置 连接池,然后配置数据源。配好后,其 config.xml 文件中的相应内容如下: ………… ………… 在配置结束后,就可以写程序来获取数据源了,其步骤如下: a. 通过 JNDI 查找数据源。 Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("kingbase_Data_Source"); b. 使用数据源以获得数据库连接,并处理 SQL 语句操作。 Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT name,nick FROM tu9 "); while (rs.next()) { out.println(rs.getString("name") + " " + rs.getString("nick")); } 263 第 14 章 在应用服务器中配置 JDBC 例 14-2. 使用 Weblogic 建立连接 此程序的格式是 JAVA 的 Servlet 格式的程序,注意使用时要在相应的 web.xml 文件中添加相应的配置。 import java.io.*; import java.sql.*; import javax.servlet.http.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.util.*; import com.kingbase8.jdbc3.*; public class example3 extends HttpServlet { public void init() { try { ctx = new InitialContext(); } catch (Exception E) { E.printStackTrace() ;; } } public void service(HttpServletRequest requ, HttpServletResponse resp) throws IOException { Connection conn = null; try { PrintWriter out = resp.getWriter(); out.println(""); out.println("use DataSource from JNDI" + ""); out.println(""); out.println("

use DataSource from JNDI

"); try { DataSource ds = (DataSource)ctx.lookup( 264 第 14 章 在应用服务器中配置 JDBC "weblogic.jdbc.pool.commercePool"); conn = ds.getConnection(); stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT name,nick FROM tu9 "); while (rs.next()) { out.println(rs.getString("name") + "- " + rs.getString("nick") + "- " + "

"); } } catch(SQLException e) { e.printStackTrace() ; } catch(NamingException e) { e.printStackTrace() ; } } catch (Exception E) { E.printStackTrace() ; } finally { if (rs != null) { try { rs.close(); } catch (Exception ignore) {}; } if (stmt != null) { try { stmt.close(); } catch (Exception ignore) {}; } if (conn != null) { try { conn.close(); } catch (Exception ignore) {}; } } } static Context ctx; 265 第 14 章 在应用服务器中配置 JDBC javax.sql.DataSource ds; Statement stmt; ResultSet rs; } 第四步:应用程序中引用,编程方法如下: …………example3example3/servlet-class>example3/………… 14.3 Tomcat Tomcat 在启动之前,需要配置其 server.xml 文件和 web.xml 文件,以便 Tomcat 可以加载 KingbaseES JDBC 驱动。 在 Tomcat 的 webapps 目录下建立文件夹 DBTest (tomcatwebappsDBTest). 把 kingbase8jdbc.jar 驱动程序拷贝到 \tomcatcommonlib\ 目录下。 server.xml 文件配置格式如下:(位于路径”$CATALINA_HOME/conf/server.xml.”) …………………… …………………… web.xml 文件配置格式如下:(位于工作路径”tomcatwebappsDBTestWEB-INFweb.xml”) Kingbase Test AppDB Connectionjdbc/TestDBjavax.sql.DataSourceContainer 在配置结束后,就可以写程序来获取数据源了,其步骤如下:(可参考 Tomcat 自带的文件说明--《JNDI Datasource HOW-TO》) a. Database Connection Pool (DBCP) Configurations DBCP 包括如下 jar 文件: commons-dbcp/commons-dbcp2 commons-pool/commons-pool2 这些 jar 文件应该位于”$CATALINA_HOME/common/lib” 路径下。 b. 测试代码: a. 先编写一个 jsp 文件,放置于 \tomcatwebappsDBTest\ 目录下:test.jsp DB Test<% 267 第 14 章 在应用服务器中配置 JDBC kb.DBTest tst = new kb.DBTest(); tst.init(); %>

Results

Name<%= tst.getName() %>
Age<%= tst.getAge() %> b. 使用数据源和连接池建立一个 java 文件,放置于 \tomcatwebappsDBTestweb-infclasseskb\ 目录下: 例 14-3. 使用 Tomcat 建立连接 在 linux 中 kingbase 安装在 /opt/Kingbase/ES/V9 下,需要对数据库 test 作一次完全备份,备份到 /home/ kingbase/backup 目录下, package kb; import javax.naming.*; import javax.sql.*; import java.sql.*; public class DBTest { String name = "Not Connected"; int age = -1; public void init() { try { Context ctx = new InitialContext(); if(ctx == null ) throw new Exception("Exception message:No Context"); DataSource ds = (DataSource)ctx.lookup( "java:comp/env/jdbc/TestDB"); if (ds != null) { Connection conn = ds.getConnection(); if(conn != null) { name = "Got Connection "+conn.toString(); Statement stmt = conn.createStatement(); 268 第 14 章 在应用服务器中配置 JDBC ResultSet rst = stmt.executeQuery( "select name, age from testdata"); if(rst.next()) { name=rst.getString(1); age=rst.getInt(2); } conn.close(); } } } catch(Exception e) { e.printStackTrace(); } } public String getName() { return name; } public int getAge() { return age;} } 269 版权声明 版权声明 北京人大金仓信息技术股份有限公司(简称:人大金仓)版权所有,并保留对本手册及本声明的一切权利。 未得到人大金仓的书面许可,任何人不得以任何方式或形式对本手册内的任何部分进行复制、摘录、备份、修 改、传播、翻译成其他语言、将其全部或部分用于商业用途。 免责声明 本手册内容依据现有信息制作,由于产品版本升级或其他原因,其内容有可能变更。人大金仓保留在没有任何通 知或者提示的情况下对手册内容进行修改的权利。 本手册仅作为使用指导,人大金仓在编写本手册时已尽力保证其内容准确可靠,但并不确保手册内容完全没有错 误或遗漏,本手册中的所有信息也不构成任何明示或暗示的担保。 技术支持 • 人大金仓官方网站:http://www.kingbase.com.cn/ • 人大金仓文档中心:http://help.kingbase.com.cn/ • 全国服务热线:400-601-1188 • 人大金仓技术支持与反馈信箱:support@kingbase.com.cn 270 服务周期承诺 服务周期承诺 由于市场需求在不断变化,技术创新和发展的进程不断加剧,产品的版本更迭不可避免。人大金仓对于产品版本 生命周期的有效管理,有助于您提前规划项目,更好地从产品服务终止上过渡。 表 1: KingbaseES 产品生命周期里程碑 关键里程碑点 定义 产品发布日期 产品正式发布版本,即 GA(general availability)版本的发布日期。 停止销售日期 正式停止销售的日期,版本停止接受订单日。该日之后,产品将不再销售。 停止功能升级日期 在该日期之后,不再提供新特性和新硬件支持。但依旧提供错误修复、安全修复、功 能维护等服务。 停止功能维护日期 在该日期之后,不再维护功能,修复问题。但依旧提供安全修复等服务 停止安全维护日期 在该日期之后,不再发布补丁版本修复中高风险漏洞,仅提供有限的支持。 产品服务终止日期 停止提供产品服务和支持的日期。包括软件维护版本,缺陷修复,以及针对该产品的 所有服务支持(包括服务热线和远程/现场支持)。 服务周期策略 金仓数据库管理系统 KingbaseES 产品确保以下的服务周期: 1)产品自发布之日起至产品停止功能升级(包含新特性、新硬件支持)之日不少于 5 年。 2)产品停止功能升级之日起至产品停止功能维护(主要包括问题修复)之日不少于 4 年。 3)产品功能维护停止之日起至产品停止安全维护(包括中高风险漏洞修复)之日不少于 2 年。 服务终止策略 金仓数据库管理系统 KingbaseES 产品确保在销售后,至少提供 6 年的服务支持。 注意: 人大金仓将会综合各方因素来确定产品服务终止日期。并将在实际产品服务终止日期之前至少 90 天,通过公 271 服务周期承诺 开方式宣布产品服务终止日期。 272

相关文章