跳到主要内容

执行数据库操作

本主题主要描述如何使用 GBase 8s JDBC Driver 来执行对 GBase 8s 数据库的操作。

查询数据库

对于将查询发送至数据库以及检索结果,GBase 8s JDBC Driver 遵守 JDBC API 规范。驱动程序支持 Statement、PreparedStatement、CallableStatement、ResultSet 和 ResultSetMetaData 接口的大多数方法。

将查询发送至 GBase 8s 数据库的示例

下列来自 SimpleSelect.java 程序的示例展示如何使用 PreparedStatement 接口,来执行有一个输入参数的 SELECT 语句:

try
{
PreparedStatement pstmt = conn.prepareStatement("Select *
from x "
+ "where a = ?;");
pstmt.setInt(1, 11);
ResultSet r = pstmt.executeQuery();
while(r.next())
{
short i = r.getShort(1);
System.out.println("Select: column a = " + i);
}
r.close();
pstmt.close();
}
catch (SQLException e)
{
System.out.println("ERROR: Fetch statement failed: " +
e.getMessage());
}

该程序首先使用 Connection.prepareStatement() 方法来以它的单个输入参数准备 SELECT 语句。然后,它通过使用PreparedStatement.setInt() 方法来将值赋予该参数,并以 PreparedStatement.executeQuery() 方法来执行该查询。

该程序返回 ResultSet 对象中的结果行,该程序以 ResultSet.next() 方法通过其重复执行。该程序以 ResultSet.getShort() 方法来检索单独的列值,因为选中列的数据类型为 SMALLINT。

最后,以恰当的 close() 方法来同时显式地关闭 ResultSet 和PreparedStatement对象。

要获取关于哪些 getXXX() 方法检索单独的列值的更多信息,请参阅 ResultSet.getXXX() 方法的数据类型映射。

结果集

Statement.execute() 方法的 GBase 8s JDBC Driver 实现返回单个 ResultSet 对象。因为服务器不支持多个 ResultSet 对象,因此,此实现与 JDBC API 规范不同, JDBC API 规范规定 Statement.execute() 方法可返回多个 ResultSet 对象。

GBase 8s JDBC Driver 不支持返回多个结果集。

多行的可滚动结果集

“可滚动结果集”一次从服务器访存一行。对“可滚动结果集”的性能提升允许一次访存多行。在下列示例中,期望得到行 m 至行 n,将这些行访存至 ResultSet 内。只要仅访问包括在 m 与 n 之间的行,就不会发生进一步访存。在此示例中,期望得到行 50 至行 100,且 ResultSet 为 SCROLL_INSENSITIVE:

rs.setFetchSize(51);
rs.absolute(49); // one row will be fetched
rs.next() // rs will contain 51 rows

GBase 8s 仅向前访存且仅访存一行,除非使用 DIR_NEXT 访存来访存行。对于 DIR_NEXT 操作,服务器发送行,直到填满访存缓冲区为止,或直到发送最后一行为止。仅 ResultSet.next() 可生成 DIR_NEXT 操作。

此性能提升不更改 FORWARD_ONLY ResultSet 的行为。不更改访存缓冲区大小的计算。

对于 SCROLL_INSENTIVE ResultSet,由访存大小和行大小来确定访存缓冲区的大小。可使用 Statement.setFetchSize() 和ResultSet.setFetchSize() 来设置访存大小。如果访存大小为零,则使用缺省的访存缓冲区大小。将访存缓冲区大小限定为 32 K。

某些 ResultSet methods 需要关于由查询生成的行数的信息。这些方法可能导致访存一行来获取信息,然后重新访存当前行。这些方法是isBeforeFirst()、isLast() 和 absolute(-row)。

此外,setMaxRows() 可为 SCROLL_INSENSITIVE ResultsSet 更改访存缓冲区大小。由于需要附加的服务器支持来确保高效地使用setMaxRows(),在此时不推荐使用 ResultSet.setMaxRows()。

释放资源

当已结束处理 SQL 语句的结果时,通过在 Java™ 程序中调用恰当的 close() 方法,来关闭 Statement、PreparedStatement 和CallableStatement 对象。此关闭立即释放已分配来执行 SQL 语句的那些资源。虽然 ResultSet.close() 方法关闭 ResultSet 对象,但它不释放分配给 Statement、PreparedStatement 或 CallableStatement 对象的资源。

当已结束处理 SQL 语句的结果时,调用 ResultSet.close() 和 Statement.close() 方法,来指示您以该语句或结果集处理的 GBase 8s JDBC Driver,这是一种好的做法。当您这么做时,程序释放数据库服务器上的所有资源。然而,不需要特意地调用 ResultSet.close() 和 Statement.close(),只要调用负责释放这些资源的 Connection.close() 即可。

跨线程执行

不可跨线程地并发访问同一 Statement 或 ResultSet 实例。然而,您可在多个线程之间共享一个 Connection 对象。

例如,如果一个线程在 Statement 对象上执行 Statement.executeQuery() 方法,另一个线程在同一 Statement 对象上执行Statement.executeUpdate() 方法,则难以预料两个方法的结果,且依赖于最后执行了哪个方法。

类似地,如果一个线程执行方法 ResultSet.next(),另一线程在同一 ResultSet 对象上执行同一方法,则难以预料两个方法的结果,且依赖于最后执行了哪个方法。

滚动游标

GBase 8s JDBC Driver 的滚动游标特性遵循 JDBC 3.0 规范,有这些例外:

滚动灵敏性

滚动游标的 GBase 8s 数据库服务器实现将访存的行置于临时表中。如果另一进程更改原始表中的一行(假定未锁定该行),且再次访存该行,则这些更改对于客户机是不可见的。

此行为类似于 JDBC 3.0 规范中的 SCROLL_INSENSITIVE 描述。GBase 8s JDBC Driver 不支持 SCROLL_SENSITIVE 游标。要看到更新了的行,客户机应用程序必须关闭并重新打开该游标。

客户机侧滚动

JDBC 规范表明,可在客户机侧结果集上发生滚动。GBase 8s JDBC Driver 仅支持结果集的滚动达到数据库服务器支持滚动的程度。

结果集可更新性

对于产生可更新的结果集的 SQL 查询,JDBC 3.0 API 不提供严格的规范。通常,满足下列条件的查询可产生可更新的结果集:

  • 该查询仅引用数据库中的单个表。
  • 该查询不包含任何 JOIN 操作。
  • 该查询选择它引用的表的主键。
  • 选择列表中的每个值表达式都必须由列规范组成,且没有列规范可出现多次。
  • 表表达式的 WHERE 子句不可包括子查询。

GBase 8s JDBC Driver 放松对主键的要求,因为该驱动程序执行下列操作:

  1. 驱动程序查找称为 ROWID 的列。
  2. 驱动程序在表中查找 SERIAL、SERIAL8 或 BIGSERIAL 列。
  3. 驱动程序在系统目录中查找表主键。

如果这些都不提供,则驱动程序返回错误。

当您删除结果集中一行时,会影响 ResultSet.absolute() 方法,因为在删除之后行的位置更改了。

当查询包含 SERIAL 列,且在多行中复制该数据时,则 updateRow() 或 deleteRow() 的执行会影响包含该数据的所有行。

ScrollCursor.java 示例文件展示如何检索带有滚动游标的结果集。要了解如何使用可更新的可滚动游标的示例,请参阅UpdateCursor1.java、UpdateCursor2.java 和 UpdateCursor3.java 文件。

注意

目前SERVER不支持TYPE_SCROLL_INSENSITIVE和TYPE_SCROLL_SENSITIVE结果集类型,所以JDBC仅支持TYPE_FORWARD_ONLY默认类型。

保持游标

当使用事务日志记录时,当事务结束时,GBase 8s 通常关闭所有游标并释放所有锁。在多用户环境中,这种行为并不总是可取的。

GBase 8s JDBC Driver 已经以 GBase 8s 扩展实现了可保持的游标支持。 GBase 8s 数据库服务器支持在游标的声明中添加关键字 WITH HOLD。这样的游标称为保持游标,且在事务结束时不关闭。

为符合 JDBC 3.0 规范,GBase 8s JDBC Driver 将方法添加至 JDBC 接口,以支持可保持的游标。

要获取关于保持游标的更多信息,请参阅《GBase 8s SQL 指南:语法》。

更新数据库

可发出批量更新语句,或执行批量插入来更新数据库。

执行批量更新

批量更新特性类似于多条 GBase 8s SQL PREPARE 语句。可如下列示例中那样发出批量更新语句:

PREPARE stmt FROM "insert into tab values (1);
insert into tab values (2);
update table tab set col = 3 where col = 2";

GBase 8s JDBC Driver 中的批量更新特性遵守 JDBC 3.0 规范,有这些例外:

  • SQL 语句
  • 从 Statement.executeBatch() 返回值

SQL 语句和批量更新

不可将下列命令放入多语句 PREPARE 语句内:

  • SELECT(SELECT INTO TEMP 除外)语句
  • DATABASE 语句
  • CONNECTION 语句

要了解详细信息,请参阅《GBase 8s SQL 指南:语法》。

从 Statement.executeBatch() 方法返回值

以下列方式,返回值不同于 JDBC 3.0 规范:

  • 如果将 IFX_BATCHUPDATE_PER_SPEC 环境变量设置为 0,则仅返回批量中执行的第一个语句的更新数。如果将IFX_BATCHUPDATE_PER_SPEC 环境变量设置为 1(缺省值),则返回值等于由 Statement.executeBatch() 执行的所有 SQL 语句影响的行数。要获取更多信息,请参阅 随同 GBase 8s JDBC 驱动程序的 GBase 8s 环境变量。
  • 当在 Statement 对象中执行的批量更新中发生错误时,该语句不影响行;不执行该语句。在此情况下,调用BatchUpdateException.getUpdateCounts() 会返回 0。
  • 当在 PreparedStatement 对象中执行的批量更新中发生错误时,在数据库服务器上成功地插入了或更新了的行不恢复它们的更新前状态。然而,不是始终提交这些语句;它们仍处于基本的 autocommit 模式。

BatchUpdate.java 示例文件展示如何将批量更新发送至数据库服务器。

执行批量插入

批量插入是对 JDBC 3.0 批量更新特性的 GBase 8s 扩展。批量插入特性以多个值设置,来提升多次执行的单条 INSERT 语句的性能。要启用此特性,请将 IFX_USEPUT 环境变量设置为 1。(缺省值为 0。)

对于在同一 PreparedStatement 实例中传递的多条语句,或对于 INSERT 之外的语句,此特性不起作用。如果启用此特性,且在由不带参数的语句后跟的 INSERT 语句中传递,则忽略不带参数的语句。

对于除 opaque 类型或复合类型之外的所有数据类型,批量插入特性要求客户机转换 Java™ 类型,以便与服务器上的目标列类型相匹配。

在安装 JDBC 驱动程序的 demo 目录中安装 BulkInsert.java 示例,其展示如何执行批量插入。

参数、转义语法和不受支持的方法

本部分包含下列信息:

  • 如何使用 OUT 参数
  • 如何在 CallableStatement 中使用命名了的参数
  • 支持 DESCRIBE INPUT 语句
  • 如何使用转义语法来由 JDBC 翻译为 GBase 8s

它还罗列不受支持的方法,以及行为不同于标准的方法。

CallableStatement OUT 参数

CallableStatement 方法以 C 函数和 Java™ 用户定义的例程(UDR)来处理 OUT 参数。两个 registerOutParameter() 方法将 OUT 参数的数据类型指定给驱动程序。一系列 getXXX() 方法检索 OUT 参数。

JDBC CallableStatement 接口为检索 OUT 参数提供方法。

随同 GBase 8s,对于 BINARY OUT 参数,OUT 参数例程使得 JDBC 客户机可用有效的 blob 描述符和数据。使用 GBase 8s JDBC Driver Version 3.0 及后来的版本中的接收方法,可使用服务器提供的这些 OUT 参数描述符和数据。

在 GBase 8s 与 JDBC 之间交换描述符和数据,这与现有的机制相一致,为 JDBC 的结果集方法交换数据,诸如通过 SQLI 协议方法来传递 blob 描述符和数据。(SPL UDR 是支持 BINARY OUT 参数的唯一 UDR 类型。)

要了解背景信息,请参阅下列资料:

  • 对于 GBase 8s 数据库中的使用,GBase 8s 用户定义的例程和数据类型开发者指南 提供关于 opaque 类型和用户定义的例程(UDR)的介绍性和背景信息。
  • 对于在数据库服务器中的使用,J/Foundation 开发者指南 描述如何编写 Java UDR。
  • GBase 8s SQL 指南:教程 描述如何编写存储过程语言(SPL)例程。
  • GBase 8s DataBlade API 程序员指南 描述如何编写外部 C 例程。

GBase 8s 数据库服务器将 OUT 参数返回至 GBase 8s JDBC Driver。GBase 8s 支持多 OUT 参数。

要获取如何使用 OUT 参数的示例,请参阅 CallOut1.java、CallOut2.java、CallOut3.java 和 CallOut4.java 示例程序,其位于安装 GBase 8s JDBC Driver 的 demo 目录的 basic 子目录中。

服务器和驱动程序约束和限制

服务器约束

此主题描述 GBase 8s 服务器的约束。它还描述对 JDBC 驱动程序及其约束进行的改善。

不可指定 INOUT 参数。

要获取更多关于 UDR 的信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 和 J/Foundation 开发者指南。

驱动程序改善

CallableStatement 对象为所有数据库服务器提供了一种以标准方式调用和执行 UDR 的方式。将执行这些 UDR 的结果作为结果集或作为 OUT 参数返回。

下列为创建用户定义的函数 myudr 的程序,带有两个 OUT 参数和一个 IN 参数,然后,执行 myudr() 函数。该示例要求对多 OUT 参数的服务器侧支持。要获取关于 UDR 的更多信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 和 J/Foundation 开发者指南。

import java.sql.*;
public class myudr {

public myudr() {
}

public static void main(String args[]) {
Connection myConn = null;
try {
Class.forName("com.gbasedbt.jdbc.Driver");
myConn = DriverManager.getConnection(
"jdbc:gbasedbt-sqli:MYSYSTEM:18551/testDB:"
+"GBASEDBTSERVER=patriot1;user=USERID;"
+"password=MYPASSWORD");
}
catch (ClassNotFoundException e) {
System.out.println(
"problem with loading GBase8sDriver\n" + e.getMessage());
}
catch (SQLException e) {
System.out.println(
"problem with connecting to db\n" + e.getMessage());
}
try {
Statement stmt = myConn.createStatement();
stmt.execute("DROP FUNCTION myudr");
}
catch (SQLException e){
}
try
{
Statement stmt = myConn.createStatement();

stmt.execute(
"CREATE FUNCTION myudr(OUT arg1 int, arg2 int, OUT arg3 int)"
+" RETURNS boolean; LET arg1 = arg2; LET arg3 = arg2 * 2;"
+"RETURN 't'; END FUNCTION;");
}
catch (SQLException e) {
System.out.println(
"problem with creating function\n" + e.getMessage());
}

Connection conn = myConn;

try
{
String command = "{? = call myudr(?, ?, ?)}";
CallableStatement cstmt = conn.prepareCall (command);

// Register arg1 OUT parameter
cstmt.registerOutParameter(1, Types.INTEGER);

// Pass in value for IN parameter
cstmt.setInt(2, 4);

// Register arg3 OUT parameter
cstmt.registerOutParameter(3, Types.INTEGER);

// Execute myudr
ResultSet rs = cstmt.executeQuery();

// executeQuery returns values via a resultSet
while (rs.next())
{
// get value returned by myudr
boolean b = rs.getBoolean(1);
System.out.println("return value from myudr = " + b);
}

// Retrieve OUT parameters from myudr
int i = cstmt.getInt(1);
System.out.println("arg1 OUT parameter value = " + i);

int k = cstmt.getInt(3);
System.out.println("arg3 OUT parameter value = " + k);

rs.close();
cstmt.close();
conn.close();
}
catch (SQLException e)
{
System.out.println("SQLException: " + e.getMessage());
System.out.println("ErrorCode: " + e.getErrorCode());
e.printStackTrace();
}
}
}
- - -
.../j2sdk1.4.0/bin/java ... myudr
return value from myudr = true
arg1 OUT parameter value = 4
arg3 OUT parameter value = 8
驱动程序约束和限制

GBase 8s JDBC Driver 有下列关于 OUT 参数的要求和限制:

  • CallableStatement.getMetaData() 方法返回 NULL,直到已执行了 executeQuery() 方法为止。在已调用了 executeQuery() 之后,ResultSetMetaData 对象仅包含返回值的信息,不包含 OUT 参数。
  • 必须通过使用 setXXX() 方法来指定所有 IN 参数。在 SQL 语句中不可使用文字。例如,下列语句产生不可靠的结果:
CallableStatement cstmt = myConn.prepareCall("{callmyFunction(25, ?)}");

相反,请使用未指定文字参数的语句:

CallableStatement cstmt = myConn.prepareCall("{callmyFunction(?, ?)}");

为两个参数调用 setXXX() 方法。

  • 请不要关闭 CallableStatement.executeQuery() 方法返回的 ResultSet,直到您已通过使用 getXXX() 方法检索了 OUT 参数为止。
  • 在 SQL 语句中,不可将 OUT 参数强制转型为不同类型。例如,忽略下列强制转型:
CallableStatement cstmt = myConn.prepareCall("{callfoo(?::lvarchar, ?)}";
  • setMaxRows() 和 registerOutParameter() 方法同时取 java.sql.Types 值作为参数。有一些从 java.sql.Types 值到 GBase 8s 类型的一对多映射。

此外,有些 GBase 8s 类型不映射到 java.sql.Types 值。对 setMaxRows() 和 registerOutParameter() 的扩展修复了这些问题。请参阅IN 和 OUT 参数类型映射。

这些约束适用于处理 C、SPL 或 Java™ UDR 的 JDBC 应用程序。

IN 和 OUT 参数类型映射

如果驱动程序找不到相匹配的 GBase 8s 类型,或发现映射不明确( 多个相匹配的 GBase 8s 类型),则由 registerOutParameter(int, int)、registerOutParameter(int, int, int) 或 setNull(int, int) 方法抛出异常。 下表展示映射 CallableStatement 接口使用。星号(*)指示映射不明确。

java.sql.Typescom.gbasedbt.lang.IfxTypes
Array*IFX_TYPE_LIST IFX_TYPE_MULTISET IFX_TYPE_SET
BigintIFX_TYPE_INT8
BinaryIFX_TYPE_BYTE
Bit不受支持
BlobIFX_TYPE_BLOB
CharIFX_TYPE_CHAR (n)
ClobIFX_TYPE_CLOB
DateIFX_TYPE_DATE
DecimalIFX_TYPE_DECIMAL
Distinct*依赖于基础类型
DoubleIFX_TYPE_FLOAT
FloatIFX_TYPE_FLOAT1
IntegerIFX_TYPE_INT
Java_Object*IFX_TYPE_UDTVAR IFX_TYPE_UDTFIX
LongIFX_TYPE_BIGINT IFX_TYPE_BIGSERIAL
Longvarbinary*IFX_TYPE_BYTE IFX_TYPE_BLOB
Longvarchar*IFX_TYPE_TEXT IFX_TYPE_CLOB IFX_TYPE_LVARCHAR
Null不受支持
NumericIFX_TYPE_DECMIAL
Other不受支持
RealIFX_TYPE_SMFLOAT
Ref不受支持
SmallintIFX_TYPE_SMINT
StructIFX_TYPE_ROW
TimeIFX_TYPE_DTIME (hour to second)
TimestampIFX_TYPE_DTIME (year to fraction(5))
TinyintIFX_TYPE_SMINT
VarbinaryIFX_TYPE_BYTE
VarcharIFX_TYPE_VCHAR (n)
Nothing*IFX_TYPE_BOOL

1

此映射符合 JDBC。为了与较早版本相兼容,通过将 IFX_SET_FLOAT_AS_SMFLOAT 连接属性设置为 1,可将 JDBC FLOAT 数据类型映射至GBase 8s SMALLFLOAT 数据类型。

要避免映射不明确,请使用下列在 IfmxCallableStatement 接口中定义的对 CallableStatement 的扩展:

public void IfxRegisterOutParameter(int parameterIndex,
int ifxType) throws SQLException;

public void IfxRegisterOutParameter(int parameterIndex,
int ifxType, String name) throws SQLException;

public void IfxRegisterOutParameter(int parameterIndex,
int ifxType, int scale) throws SQLException;

public void IfxSetNull(int i, int ifxType) throws SQLException;

public void IfxSetNull(int i, int ifxType, String name) throws
SQLException;

在 IfxTypes 类 中罗列 IfxType 参数的可能的值。

JDBC 客户机可用 GBase 8s 有效的 BLOB 描述符和数据,来支持 SPL UDR 的二进制 OUT 参数。

GBase 8s JDBC Driver Version 3.0 或后来版本可接收服务器提供的 OUT 参数描述符和数据,并在 Java™ 应用程序中使用它。

对于任何通过方法 getParameterType (ParameterMetaData) 检索的任何 JDBC 二进制类型(BINARY、VARBINARY、LONGVARBINARY),单个正确的返回值为 -4,其与 java.sql.Type.LONGVARBINARY 数据类型相关联。这反映了一个事实,就是将所有 JDBC 二进制类型映射至同一GBase 8s SQL 数据类型 BYTE。

CallableStatement 中命名了的参数

CallableStatement 提供从 Java™ 程序调用服务器上的存储过程的方式。可在 CallableStatement 中使用命名了的参数来按名称而不是按次序位置标识参数。在 JDBC 3.0 规范中引入了此改善。如果过程是唯一的,则可省略有缺省值的参数,可以任何顺序输入参数。对于调用有许多参数且某些参数有缺省值的存储过程,命名了的参数特别有用。

JDBC 驱动程序忽略参数名称的大小写。如果对于所有参数,存储过程都没有名称,则服务器为丢失的名称传递一个空字符串。

对于 CallableStatement 中命名了的参数的要求和约束

对于 CallableStatement 中命名了的参数,GBase 8s JDBC Driver 有下列要求和约束:

  • 在例程的单个调用之内,必须通过名称或通过次序格式来为 CallableStatement 指定参数。例如,如果您为一个参数命名参数,则必须为所有参数使用参数名称。
  • 对于远程 CallableStatement,不支持命名了的参数。
  • 在 JDK Version 1.4.x 或后来版本上,支持命名了的参数。
  • 对于调用存储过程,对命名了的参数的支持以现有限制为准。
在 CallableStatement 中核实对命名了的参数的支持

JDBC 规范提供 DatabaseMetaData.supportsNamedParameters() 方法,来确定驱动程序和 RDMS 是否支持 CallableStatement 中命名了的参数。例如:

     Connection myConn = . . .   // connection to the RDBMS for Database
. . .
DatabaseMetaData dbmd = myConn.getMetaData();
if (dbmd.supportsNamedParameters() == true)
{
System.out.println("NAMED PARAMETERS FOR CALLABLE"
+ "STATEMENTS IS SUPPORTED");
. . .
}

如果支持命名了的参数,则系统返回 true。

检索存储过程的参数名称

要检索存储过程的参数名称,请使用 JDBC 规范定义的 DatabaseMetaData 方法,如下列示例所示。

Connection myConn = ...   // connection to the RDBMS for Database
. . .
DatabaseMetaData dbmd = myConn.getMetaData();
ResultSet rs = dbmd.getProcedureColumns(
"myDB", schemaPattern, procedureNamePattern, columnNamePattern);
rs.next() {
String parameterName = rs.getString(4);
- - - or - - -
String parameterName = rs.getString("COLUMN_NAME");
- - -
System.out.println("Column Name: " + parameterName);

显示与 getProcedureColumns() 方法的参数相匹配的所有列。

参数名称不是 ParameterMetaData 接口的一部分,不可从 ParameterMetaData 对象检索。

当您使用 getProcedureColumns() 方法时,该查询从 sysprocedures 系统目录表检索由 gbasedbt 拥有的所有过程(包括系统产生的例程)。要防止错误,请核实:已在服务器上以正确的许可配置了您正在使用的存储过程。

对于 getProcedureColumns() 方法,要了解在 JDBC API 行为中的重要差异,请参阅 不支持的方法和行为不同的方法。

命名了的参数和唯一的存储过程

唯一的存储过程有唯一的名称和唯一的参数编号。当 CallableStatement 中的参数数等于或小于存储过程中的参数数时,唯一的存储过程支持命名了的参数。

命名了的参数数等于参数数的示例

下列存储过程有五个参数

create procedure createProductDef(productname   varchar(64),
productdesc varchar(64),
listprice float,
minprice float,
out prod_id float);
. . .
let prod_id = <value for prod_id>;
end procedure;

下列带有五个参数的 Java™ 代码对应于该存储过程。JDBC 调用的圆括号内的问号(?)引用这些参数。(在此情况下,是五个参数的五个参数)。设置或注册所有参数。通过使用格式 cstmt.setString("arg", name); 来命名这些参数,在此,arg 是相应的存储过程中的参数名称。无需按照与存储过程中参数顺序相同的顺序来命名参数。

String sqlCall = "{call CreateProductDef(?,?,?,?,?)}";
CallableStatement cstmt = conn.prepareCall(sqlCall);

cstmt.setString("productname", name); // Set Product Name.
cstmt.setString("productdesc", desc); // Set Product Description.
cstmt.setFloat("listprice", listprice); // Set Product ListPrice.
cstmt.setFloat("minprice", minprice); // Set Product MinPrice.

// Register out parameter which should return the product is created.

cstmt.registerOutParameter("prod_id", Types.FLOAT);

// Execute the call.
cstmt.execute();

// Get the value of the id from the OUT parameter: prod_id
float id = cstmt.getFloat("prod_id");

Java 代码和存储过程展示下列事件的进程:

  1. 准备对存储过程的调用。
  2. 参数名称指示哪些参数对应于哪个参数值或类型。
  3. 为输入参数设置值,并注册输出参数的类型。
  4. 以输入参数作为参数来执行存储过程。
  5. 存储过程返回参数值作为输出参数,并检索输出参数的值。
命名了的参数数小于参数数的示例

如果 CallableStatement 中的参数数小于存储过程中的参数数,则剩余的参数必须有缺省值。无需为有缺省值的参数设置值,因为服务器自动地使用缺省值。然而,您必须指出没有缺省值的参数,或在 CallableStatement 中以问号(?)覆盖缺省值。

例如,如果存储过程有 10 个参数,其中 4 个没有缺省值,6 个有缺省值,则在 CallableStatement 中必须有至少 4 个问号。或者,可使用 5、6,或最多 10 个问号。

如果以多于无缺省值但少于存储过程参数数的参数准备 CallableStatement,则它必须为无缺省值参数设置值。剩余的参数可为任何其他参数,且可随同每一执行来更改它们。

在下列唯一的存储过程中,参数 listprice 和 minprice 有缺省值:

create procedure createProductDef(productname   varchar(64),
productdesc varchar(64),
listprice float default 100.00,
minprice float default 90.00,
out prod_id float);
. . .
let prod_id = <value for prod_id>;
end procedure;

下列 Java™ 代码以少于存储过程中参数的参数调用存储过程(五个参数的四个参数)。由于 listprice 有缺省值,因此,可从 CallableStatement 省略它。

String sqlCall = "{call CreateProductDef(?,?,?,?)}";
// 4 params for 5 args
CallableStatement cstmt = conn.prepareCall(sqlCall);

cstmt.setString("productname", name); // Set Product Name.
cstmt.setString("productdesc", desc); // Set Product Description.

cstmt.setFloat("minprice", minprice); // Set Product MinPrice.

// Register out parameter which should return the product id created.

cstmt.registerOutParameter("prod_id", Types.FLOAT);

// Execute the call.
cstmt.execute();

// Get the value of the id from the OUT parameter: prod_id
float id = cstmt.getFloat("prod_id");

或者,对于同一存储过程,可省略 minprice 参数的参数。无需再次准备 CallableStatement。

     cstmt.setString("productname", name); // Set Product Name.
cstmt.setString("productdesc", desc); // Set Product Description.

cstmt.setFloat("listprice", listprice); // Set Product ListPrice.

// Register out parameter which should return the product id created.

cstmt.registerOutParameter("prod_id", Types.FLOAT);

// Execute the call.
cstmt.execute();

// Get the value of the id from the OUT parameter: prod_id
float id = cstmt.getFloat("prod_id");

或者,您可同时省略缺省参数的参数:

cstmt.setString("productname", name);
cstmt.setString("productdesc", desc);
cstmt.registerOutParameter("prod_id", Types.FLOAT);
cstmt.execute();
float id = cstmt.getFloat("prod_id");

命名的参数和重载的存储过程

如果多个存储过程有相同的名称和相同的参数数,则该过程为重载的(也称为重载的 UDR)。

对于重载的存储过程,JDBC 驱动程序抛出 SQLException,因为调用不可解析至单个存储过程。要防止 SQLException,请通过将 ::data_type附加至 data_type 为 GBase 8s 服务器数据类型处的问号字符,在参数列表中指定命名的参数的 GBase 8s 服务器数据类型。例如 ?::varchar 或?::float。您还必须为所有参数输入命名的参数,且以与重载的存储过程的参数顺序相同的顺序输入。

例如,下列两个过程有相同的名称(createProductDef)和相同的参数数。在每一过程中,prod_id 参数的数据类型不一样。

过程 1

create procedure createProductDef(productname   varchar(64),
productdesc varchar(64),
listprice float default 100.00,
minprice float default 90.00,
prod_id float);
...
let prod_id = <value for prod_id>;
end procedure;

过程 2

create procedure createProductDef(productname   varchar(64),
productdesc varchar(64),
listprice float default 100.00,
minprice float default 90.00,
prod_id int);
...
let prod_id = <value for prod_id>;
end procedure;

如果使用下列 Java™ 代码,则由于它不可解析至唯一的一个过程,因此,它返回 SQLException:

String sqlCall = "{call CreateProductDef(?,?,?,?,?)}";
CallableStatement cstmt = con.prepareCall(sqlCall);
cstmt.setString("productname", name); // Set Product Name.

如果您为有不同数据类型的参数指定 GBase 8s 数据类型,则 Java 代码解析至一个过程。下列 Java 代码解析至存储过程 1,因为代码为 prod_id参数指定 FLOAT 数据类型:

String sqlCall = "{call CreateProductDef(?,?,?,?,?::float)}";
CallableStatement cstmt = con.prepareCall(sqlCall);
cstmt.setString("productname", name); // Set Product Name

JDBC 支持 DESCRIBE INPUT

SQL 92 和 99 标准为动态 SQL 指定 DESCRIBE INPUT 语句。

JDBC 3.0 规范引入对应于 DESCRIBE INPUT 支持的 ParameterMetaData 类和方法。

GBase 8s JDBC Driver 实现 java.sql.ParameterMetaData 类。此接口用于描述准备好的语句中的输入参数。已实现了方法getParameterMetaData() 来为特别的语句检索元数据。

ParameterMetaData 类和 getParameterMetaData() 方法是 JDBC 3.0 API 的一部分,作为 J2SDK1.4.0 中的接口包括它们。在 JDBC 3.0 规范中指定这些接口的详细信息。

GBase 8s JDBC Driver 已实现了 ParameterMetaData 接口的附加方法,来扩展它的功能,如下表中所示。

返回类型方法描述
intgetParameterLength (int param)检索参数长度
intgetParameterExtendedId (int param)检索参数扩展的 ID
java.lang.StringgetParameterExtendedName (int param)检索参数扩展的名称
java.lang.StringgetParameterExtendedOwnerName (int param)检索该类型的参数扩展的所有者名称
intgetParameterSourceType (int param)检索参数 SourceType
intgetParameterAlignment (int param)检索参数对齐

下列是在 GBase 8s JDBC Driver 中使用 ParameterMetaData 接口的一个示例:

. . .
try
{
PreparedStatement pstmt = null;

pstmt = myConn.prepareStatement(
"select * from table_1 where int_col = ? "
+"and string_col = ?");
ParameterMetaData paramMeta = pstmt.getParameterMetaData();
int count = paramMeta.getParameterCount();
System.out.println("Count : "+count);

for (int i=1; i <= count; i++)
{
System.out.println("Parameter type name : "
+paramMeta.getParameterTypeName(i));
System.out.println("Parameter type : "
+paramMeta.getParameterType(i));
System.out.println("Parameter class name : "
+paramMeta.getParameterClassName(i));
System.out.println("Parameter mode : "
+paramMeta.getParameterMode(i));
System.out.println("Parameter precision : "
+paramMeta.getPrecision(i));
System.out.println("Parameter scale : "
+paramMeta.getScale(i));
System.out.println("Parameter nullable : "
+paramMeta.isNullable(i));
System.out.println("Parameter signed : "
+paramMeta.isSigned(i));
}
. . .

转义语法

转义语法指示必须从 JDBC 格式翻译为 GBase 8s 原生格式的信息。SQL 语句的有效转义语法如下:

语句的类型转义语法
过程{call procedure}
函数{var = call function}
日期{d 'yyyy-mm-dd'}
时间{t 'hh:mm:ss'}
时间戳(Datetime){ts 'yyyy-mm-dd hh:mm
.fffff
'}
函数调用{fn func[(args)]}
转义字符{escape 'escape-char'}
外部连接{oj outer-join-statement}

可在 SQL 语句中放置任意此语法,如下:

executeUpdate("insert into tab1 values( {d '1999-01-01'} )");

将方括号内的一切都转换为有效的 GBase 8s SQL 语句,并返回至调用函数。

不支持的方法和行为不同的方法

GBase 8s JDBC Driver 不支持下列 JDBC API 方法,在连接至 GBase 8s 的 Java™ 程序中不可使用:

  • CallableStatement.getRef(int)
  • Connection.setCatalog()
  • Connection.setReadOnly()
  • PreparedStatement.addBatch(String)
  • PreparedStatement.setRef(int, Ref)
  • PreparedStatement.setUnicodeStream(int, java.io.InputStream, int)
  • ResultSet.getRef(int)
  • ResultSet.getRef(String)
  • ResultSet.getUnicodeStream(int)
  • ResultSet.getUnicodeStream(String)
  • ResultSet.refreshRow()
  • ResultSet.rowDeleted()
  • ResultSet.rowInserted()
  • ResultSet.rowUpdated()
  • ResultSet.setFetchSize()
  • Statement.setMaxFieldSize()

Connection.setCatalog() 和 Connection.setReadOnly() 方法不返回错误。其他方法抛出异常:Method not Supported.

下列 JDBC API 方法的行为不同于由 JavaSoft 规范指定的行为:

  • CallableStatement.execute()

返回单个结果集

  • DatabaseMetaData.getProcedureColumns()

示例:

DBMD.getProcedureColumns(String catalog,String schemaPattern,
String procedureNamePattern,String columnNamePattern)

忽略 columnNamePattern 字段;返回 NULL。

当您使用 getProcedureColumns() 方法时,该查询从 sysprocedures 系统目录表检索由 gbasedbt 拥有的所有过程(包括系统生成的例程)。要防止错误,请在服务器上核实,已以正确的许可配置了您正在使用的存储过程。

例如,如果使用下列语句之一:

getProcedureColumns("","","","")
getProcedureColumns("",gbasedbt,"","")

DatabaseMetaData.getProcedureColumns() 方法加载所有服务器 UDR 和由用户 gbasedbt 拥有的 UDR。如果选择不安装J/Foundation,或在 onconfig 文件中未将 J/Foundation 的配置参数设置为有效值,则方法失败。此外,如果未在服务器上正确地建立任何一个 UDR,则方法失败。

要获取关于如何在 GBase 8s 服务器上建立 J/Foundation,以及如何在 GBase 8s 服务器上运行 Java UDR 的信息,请参阅 J/Foundation 开发者指南。要获取关于如何建立和运行 C UDR 的信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 。

  • DatabaseMetaData.othersUpdatesAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.othersDeletesAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.othersInsertsAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.ownUpdatesAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.ownDeletesAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.ownInsertsAreVisible()

    始终返回 FALSE

  • DatabaseMetaData.deletesAreDetected()

    始终返回 FALSE

  • DatabaseMetaData.updatesAreDetected()

    始终返回 FALSE

  • DatabaseMetaData.insertsAreDetected()

    始终返回 FALSE

  • PreparedStatement.execute()

    返回单个结果集

  • ResultSet.getFetchSize()

    始终返回 0

  • ResultSetMetaData.getCatalogName()

    始终返回包含一个空格的 String 对象

  • ResultSetMetaData.getTableName()

    返回 SELECT、INSERT 和 UPDATE 语句的表名称

    带有多个表名称的 SELECT 和所有其他语句返回包含一个空格的 String 对象。

  • ResultSetMetaData.getSchemaName()

    始终返回包含一个空格的 String 对象

  • ResultSetMetaData.isDefinitelyWriteable()

    始终返回 TRUE

  • ResultSetMetaData.isReadOnly()

    始终返回 FALSE

  • ResultSetMetaData.isWriteable()

    始终返回 TRUE

  • Statement.execute()

    返回单个结果集

  • Connection.isReadOnly()

    仅当连接至 HAC 常见中的辅助服务器时,返回 TRUE(请参阅下列重要说明)

重要

GBase 8s 服务器当前不支持只读连接。对于 GBase 8s JDBC,已更改了来自 java.sql.Connection 接口的 setReadOnly() 方法的实现,以通过调用进程来接收传给它的值。setReadOnly() 方法只是返回调用进程,不与 GBase 8s 数据库服务器发生任何交互。(先前版本的 JDBC 驱动程序会抛出不支持方法异常。)

处理事务

在缺省情况下,所有新的 Connection 对象都处于 autocommit 模式。当打开 autocommit 模式时,在发送至数据库服务器的每一语句之后,都自动地执行 COMMIT 语句。要关闭 autocommit 模式,请显式地调用 Connection.setAutoCommit(false)。

当 autocommit 模式关闭时,当将下一语句发送至数据库服务器时,GBase 8s JDBC Driver 隐式地启动新的事务。此事务持续,直到用户发出 COMMIT 或 ROLLBACK 语句为止。如果用户通过执行 setAutoCommit(false) 已启动了事务,然后再次调用 setAutoCommit(false),则现有的事务继续保持不变。在 Java™ 程序删除至数据库或数据库服务器的连接之前,它必须通过发出 COMMIT 或 ROLLBACK 语句来显式地终止事务。

在事务期间,如果 Java 程序设置 autocommit 模式为打开,则 GBase 8s JDBC Driver 提交当前的事务,如果 JDK 是 1.4 版本和后来版本的话。否则,在打开 autocommit 之前,驱动程序回滚当前事务。

在以日志记录创建了的数据库中,如果将 COMMIT 语句发送至数据库服务器,且 autocommit 模式为打开,则数据库服务器返回错误 -255: Not in transaction,因为当前未启动用户事务。不管以 Connection.commit() 方法还是直接以 SQL 语句发送了 COMMIT 语句,都发生此情况。

在以 ANSI 模式创建的数据库中,显式地将 COMMIT 语句发送至数据库服务器,会提交一个空事务。如果当前没有打开用户事务,则由于数据库服务器在执行语句之前自动地启动事务,因此,不返回错误。

对于 XAConnection 对象,缺省情况下 autocommit 模式是关闭的,当分布式事务正在发生时,必须保持关闭。事务管理器执行提交和回滚操作;因此,请避免直接执行这些操作。

对于 GBase 8s,两个 JDBC 类支持在遇到不利事件之后可将 SQL 事务回滚至保存点(而不是完全取消):

  • IfmxSavepoint(接口)
  • IfxSavepoint(Savepoint 类)

通过下列标准 JDBC 方法,JDBC 应用程序可创建、删除或回滚到保存点对象:

表 1. JDBC 保存点类和方法

方法
IfxConnectionsetSavepoint()releaseSavepoint()rollback(savepoint)
IfxSavepointgetSavepointId()getSavepointName()
这两个方法不可互换。调用 getSavepointName() 会出错失败,除非以 setSavepoint() 方法的或 setSavepointUnique() 方法的字符串参数来声明保存点对象。类似地,如果调用命名的保存点对象的 getSavepointId(),则返回错误。

此外,setSavepointUnique() 方法可设置其标识符为唯一的命名的保存点。当唯一的保存点是活动的时,如果应用程序尝试在同一连接内重新使用它的名称,则 GBase 8s 发出异常。

下列约束适用于 JDBC 中的保存点对象:

  • 在 XA 事务内,保存点无效。
  • 不可使用保存点,除非当前连接设置 autocommit 模式为关闭。
  • 在至不记录日志的数据库的连接中,保存点无效。
  • 在触发了的活动中不可引用保存点。
  • 在跨服务器的分布式查询中,其中任何参与的从属服务器都不支持保存点对象,在连接至不支持保存点的服务器之后,如果设置一保存点,则发出警告,且任何对 rollbacksavepoint 的调用都出错失败。

要获取关于在 SQL 事务中使用保存点的更多信息,请参阅《GBase 8s SQL 指南:语法》 中对 SAVEPOINT、RELEASE SAVEPOINT 和 ROLLBACK WORK TO SAVEPOINT 语句的描述。

处理错误

在 Java™ 程序中使用 JDBC API SQLException 类来处理错误。在 Java 程序之外,也可使用特定于 GBase 8s 的 com.gbasedbt.jdbc.Message类,来检索对于给定错误编号的 GBase 8s 错误文本。

以 SQLException 类来处理错误

每当发生来自 GBase 8s JDBC Driver 或数据库服务器的错误时,就发出 SQLException。请使用 SQLException 类的下列方法,来检索错误消息的文本、错误代码和 SQLSTATE 值:

getMessage()

返回错误

SQLException 的描述,从 java.util.Throwable 类继承此方法。

getErrorCode()

返回对应于 GBase 8s 数据库服务器或 GBase 8s JDBC Driver 错误代码的整数值

getSQLState()

返回描述 SQLSTATE 值的字符串

该字符串遵守 X/Open SQLSTATE 惯例。

所有 GBase 8s JDBC Driver 错误都有形如 -79XXX 的错误代码,诸如 -79708: Can't take null input。

要获取 GBase 8s 数据库服务器错误的列表,请参阅 《GBase 8s 错误消息》。要获取 GBase 8s JDBC Driver 错误的列表,请参阅 错误消息。

来自 SimpleSelect.java 程序的下列示例展示如何使用 SQLException 类,来通过使用 try-catch 块捕获 GBase 8s JDBC Driver 或数据库服务器错误:

try
{
PreparedStatement pstmt = conn.prepareStatement("Select *
from x "
+ "where a = ?;");
pstmt.setInt(1, 11);
ResultSet r = pstmt.executeQuery();
while(r.next())
{
short i = r.getShort(1);
System.out.println("Select: column a = " + i);
}
r.close();
pstmt.close();
}
catch (SQLException e)
{
System.out.println("ERROR: Fetch statement failed: " +
e.getMessage());
}

检索语法错误偏移量

要确定语法错误的确切位置,请使用 getSQLStatementOffset() 方法,来返回语法错误偏移量。

下列示例展示如何从 SQL 语句检索语法错误偏移量(在此示例中,其为 10):

try {
Statement stmt = conn.createStatement();
String command = "select * fom tt";
stmt.execute( command );
}
catch(Exception e)
{
System.out.println
("Error Offset :"+((IfmxConnection conn).getSQLStatementOffset() );
System.out.println(e.getMessage() );
}

捕获 RSAM 错误消息

RSAM 消息附属于 SQLCODE 消息。例如,如果 SQLCODE 消息表明不可创建表,则 RSAM 消息说明原因,可能是磁盘空间不足。

可使用 SQLException.getNextException() 方法,来捕获 RSAM 错误消息。要了解如何捕获这些消息的示例,请参阅包括在 GBase 8s JDBC Driver中的 ErrorHandling.java 程序。

以 com.gbasedbt.jdbc.Message 类来处理错误

GBase 8s 提供类 com.gbasedbt.jdbc.Message,用于基于 GBase 8s 错误编号,来检索 GBase 8s 错误消息文本。要使用此类,请直接调用 Java™ 解释程序 java,将 GBase 8s 错误编号传给它,如下列示例所示:

java com.gbasedbt.jdbc.Message 100

该示例返回 GBase 8s 错误 100 的消息文本:

100: ISAM error: duplicate value for a record with unique key.

当使用 com.gbasedbt.jdbc.Message 类时,如果指定无符号数值,则返回一个正的错误编号。这不同于 finderr 实用程序,对于无符号编号,其返回负的错误编号。

访问数据库元数据

要访问关于 GBase 8s 数据库的信息,请使用 JDBC API DatabaseMetaData 接口。

GBase 8s JDBC Driver 实现 DatabaseMetaData 方法的所有 JDBC 3.0 规范。

为了符合 JDBC 3.0,已将 DatabaseMetaData 中的下列新方法添加在 GBase 8s JDBC Driver 中:

  • getSuperTypes()
  • getSuperTables()
  • getAttributes()
  • getResultSetHoldability()
  • getDatabaseMajorVersion()
  • getDatabaseMinorVersion()
  • getJDBCMajorVersion()
  • getJDBCMinorVersion()
  • getSQLStateType()
  • locatorsUpdateCopy()
  • supportsGetGeneratedKeys()
  • supportsMultipleOpenResults()
  • supportsNamedParameters()
  • supportsGetGeneratedKeys()
  • supportsMultipleOpenResults()

从 GBase 8s JDBC Driver 3.0 开始,已实现了检索服务器生成键的方法。检索自动生成的键,涉及下列活动:

  1. JDBC 应用程序编程人员提供要执行的 SQL 语句。
  2. 服务器执行 SQL 语句,并返回可检索自动生成键的标示。
  3. 在服务器执行 SQL 语句之前,验证 columnNames 或 columnIndexes(如果提供了的话)。如果它们无效,则抛出 SQLException。
  4. 如果请求,则 JDBC 驱动程序和服务器返回 resultSet 对象。如果未生成键,则 resultSet 为空,不包含任何行或列。
  5. 用户可请求 resultSet 对象的元数据,且 JDBC 驱动程序和服务器返回 resultSetMetaData 对象。

要获取关于检索自动生成的键的更多信息,请参阅“JDBC 3.0 规范”13.6 部分“检索自动产生的键”。

GBase 8s JDBC Driver 使用 sysmaster 数据库来取得数据库元数据。如果您想要在 Java™ 程序中使用 DatabaseMetaData 接口,则在 Java 程序连接到的 GBase 8s 数据库服务器中,必须存在 sysmaster 数据库。

GBase 8s JDBC Driver 解释 JDBC API 术语 schemas,来表示拥有表的 GBase 8s 用户的意思。DatabaseMetaData.getSchemas() 方法返回在systables 系统目录的 owner 列中找到的所有用户。

类似地,GBase 8s JDBC Driver 解释 JDBC API 术语 catalogs,来表示 GBase 8s 数据库的名称的意思。DatabaseMetaData.getCatalogs() 方法返回 Java 程序连接到的 GBase 8s 数据库服务器中当前存在的所有数据库的名称。

示例 DBMetaData.java 展示如何使用 DatabaseMetaData 和 ResultSetMetaData 接口,来收集关于新过程的信息。要获取关于此示例的更多信息,请参考 示例代码文件。

对 JDBC API 的其他 GBase 8s 扩展

本部分描述在此指南中尚未讨论的对 JDBC API 的特定于 GBase 8s 的扩展。这些扩展处理特定于 GBase 8s 数据库的信息。

在 处理错误 中,全面地描述另一 GBase 8s 扩展,com.gbasedbt.jdbc.Message 类。

“自动释放”特性

如果启用 GBase 8s“自动释放”特性,则当数据库服务器关闭游标时,它自动释放该游标。因此,应用程序不必发送两个单独的请求,来关闭然后再释放游标—关闭游标就足够了。

可通过在数据库 URL 中将 IFX_AUTOFREE 变量设置为 TRUE,来启用“自动释放”特性,如此示例所示:

jdbc:gbasedbt-sqli://123.45.67.89:1533:GBASEDBTSERVER=myserver;
user=rdtest;password=test;ifx_autofree=true;

还可使用下列方法之一:

public void setAutoFree (boolean flag)
public boolean getAutoFree()

在 executeQuery() 方法之前,应调用 setAutoFree() 方法,但在 executeQuery() 之前或之后,都可调用 getAutoFree()。

要使用这些方法,应用程序必须从 GBase 8s 软件包 com.gbasedbt.jdbc 导入这些类,并将 Statement 类强制转型为 IfmxStatement 类,如下所示:

import com.gbasedbt.jdbc.*;
...
(IfmxStatement)stmt.setAutoFree(true);

获取驱动程序版本信息

有两种获取关于 GBase 8s JDBC Driver 的版本信息的方式: 从 Java™ 程序,或从 UNIX™ 或 MS-DOS 命令提示。

要从 Java 程序取得版本信息,请:

  1. 通过将下列行添加至 import 部分,将 GBase 8s 软件包 com.gbasedbt.jdbc.* 导入至 Java 程序内:

    import com.gbasedbt.jdbc.*;
  2. 调用静态方法 Driver.getJDBCVersion()。

    此方法返回包含当前 GBase 8s JDBC Driver 的完全版本的 String 对象。

    GBase 8s JDBC Driver 版本的一个示例为 2.00.JC1。

    Driver.getJDBCVersion() 方法仅返回版本,不返回在驱动程序安装期间提供的序列号。

重要

对于 GBase 8s JDBC Driver 的版本 X.Y,JDBC API 方法 Driver.getMajorVersion() 和 DatabaseMetaData.getDriverMajorVersion() 始终返回值 X。类似地,方法 Driver.getMinorVersion() 和 DatabaseMetaData.getDriverMinorVersion() 始终返回值 Y。

要从命令行取得 GBase 8s JDBC Driver 的版本,请在 UNIX shell 提示或 Windows™ 命令提示处,输入下列命令:

java com.gbasedbt.jdbc.Version

该命令还返回当您安装驱动程序时提供的序列号。

JDBC驱动新增getObject方法

JDBC驱动新增getObject(int,Class)接口实现。该方法可以通过判断Class类型的具体类型,覆盖了所有目前驱动已经支持的get方法。对于不支持的其他类型,仍然抛出SQLException(IfxErrMsg.S_MTHNSUPP)异常。目前支持的Class类型如下:

String、BigDecimal、Boolean、Byte、Short、Integer、Long、Float、Double、byte[]、java.sql.Date、java.sql.Time、java.sql.Timestamp、java.sql.Clob、java.sql.Blob、java.sql.Array、java.time.LocalDateTime、java.time.LocalDate、java.time.LocalTime

JDBC驱动新增方法

JDBC 4.0 规范引入以下类和方法:

  1. JDBC驱动中新增java.sql.Blob类中的方法:

    Blob接口提供了用于获取BLOB值的长度,用于在客户端上实体化Blob值,以及用于确定Blob值中字节模式的位置。此外,该接口还具有更新BLOB值的方法。

    free()可以释放Blob对象,同时释放掉他占有的资源。如果发生错误,释放Blob的资源,抛出异常SQLException。

    getBinaryStream(long pos,long length)用于检索Blob数据类型,使用该方法返回一个包含部分Blob值的InputStream对象,该值从pos指定的字节开始。如果pos小于1,或者pos大于Blob中的字节数,又或者pos +的长度大于Blob中的字节数,则抛出SQLException。

  2. JDBC驱动中新增java.sql.Clob类中的方法:

    Clob接口提供了获取CLOB(字符大对象)值的长度,用于在客户端上实现Clob值,以及在Clob值中搜索子字符串或Clob对象的方法。接口结果集、计算表语句和准备语句中的方法,如getClob和setClob,允许程序员访问CLOB值。此外,该接口还具有更新CLOB值的方法。

    free()可以释放Clob对象,同时释放掉他占有的资源,如果发生错误,释放Clob的资源,抛出异常SQLException。

  3. JDBC驱动中新增java.sql.PreparedStatement类中的方法:

    PreparedStatement类中的方法用于预编译。SQL语句被预编译并存储在准备语句对象中。可以使用此对象多次有效地执行此语句。

    setBlob(int parameterIndex, InputStream inputStream)将指定的参数设置为InputStream对象。setBlob()方法用于为数据库中的Blob数据类型设置值。与setBinaryStream(int,InputStream)方法不同,因为它通知驱动程序,BLOB类型的参数值发送到server端。 参数索引与SQL语句中的参数标记不对应或者发生数据库访问错误时抛出异常SQLException;如果参数索引与SQL语句中的参数标记不对应,这个方法在封闭的 PreparedStatementor被调用,抛出异常SQLException。

    setBlob(int parameterIndex, InputStream inputStream, long length)将指定的参数设置为InputStream对象。输入流必须包含按长度指定的字符数,否则,在执行准备语句时将抛出SQLException. 此方法不同于setBinaryStream(int,InputStream)方法,因为它通知驱动程序,将BLOB类型的参数值发送到server端。 出现异常的第一种情况是参数索引与SQL语句中的参数标记不对应; 第二种情况发生数据库访问错误; 第三种情况这个方法在一个封闭的准备语句上被调用;第四种情况如果指定的长度小于零,或者如果输入流中的字节数与指定的长度不匹配。抛出SQLException。

    setClob(int parameterIndex, Reader reader)将指定的参数设置为Reader对象。setClob()方法用于为数据库中的Clob数据类型设置值。此方法不同于setCharacterStream(int,Reader)方法,因为它通知驱动程序,将CLOB类型的参数值发送到server端。参数索引与SQL语句中的参数标记不对应或者发生数据库访问错误时抛出SQLException;如果参数索引与SQL语句中的参数标记不对应,这个方法在封闭的 PreparedStatementor被调用,抛出异常SQLException。

    setClob(int parameterIndex, Reader reader, long length)将指定的参数设置为Reader对象。读取器必须包含按长度指定的字符数,否则,在执行准备语句时将抛出SQLException。此方法不同于setCharacterStream(int,Reader, int)方法,因为它通知驱动程序,参数值为CLOB类型发送到server端。参数索引与SQL语句中的参数标记不对应或者发生数据库访问错误时抛出SQLException ;如果指定的长度小于零;或这个方法在封闭的 PreparedStatementor被调用抛出异常SQLException 。

    setObject(int parameterIndex, Object x, SQLType targetSqlType)使用此方法来给定的对象设置指定参数的值。如果参数索引与SQL语句中的参数标记不对应或者如果发生数据库访问错误或在已关闭的准备语句上调用此方法,就会抛出SQLException。

    setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)用此方法来给定的对象设置指定参数的值。如果第二个参数是一个输入流,那么该流必须包含由scaleOrLength指定的字节数。如果第二个参数是读取器,那么读取器必须包含由“比例或长度”指定的字符数。如果参数索引不对应于SQL语句中的参数标记;如果发生数据库访问错误或在关闭的准备语句上调用此方法,或者x指定的Java对象是输入流或读取器对象,并且缩放参数的值小于零,抛出异常SQLException。

  4. JDBC驱动中新增java.sql.Resultset类中的方法:

    ResultSet接口提供了用于从当前行检索列值的getter方法(getBoolean、getLong等)。可以使用列的索引号或列名来检索值。一般来说,使用列索引会更有效率。 列从 1 开始编号。为了获得最大的可移植性,应按从左到右的顺序读取每行中的结果集列,并且每列应仅读取一次。

    rowDeleted()检索是否已删除了某个行。该方法可用于检测结果集中的孔洞。返回的值取决于此结果集对象是否可以检测到删除。如果发生数据库访问错误或在一个已关闭的结果集上调用此方法,抛出异常SQLException。

    rowInserted()检索当前行是否已有插入。返回的值取决于此结果集对象是否可以检测到可见的插入。如果发生数据库访问错误或在一个已关闭的结果集上调用此方法,抛出异常SQLException。

    rowUpdated()检索当前行是否已被更新。返回的值取决于结果集是否可以检测到更新。如果发生数据库访问错误或在一个已关闭的结果集上调用此方法,抛出异常SQLException。

  5. JDBC驱动中新增java.sql.CallableStatement类中的方法:

    CallableStatement接口是用于执行SQL存储过程。JDBC API提供了一个存储过程SQL转义语法,它允许对所有RDBMS以标准的方式调用存储过程。此转义语法有一种形式包含结果参数,另一种形式不包含结果参数。如果使用,则结果参数必须注册为OUT参数。其他参数可用于输入、输出或两者结合。参数按数字按顺序引用,第一个参数为1。

    getObject(int parameterIndex, Class type),此方法与JDBC3.0中的getObject()方法有区别,此方法中第二个参数为泛型Class,是新增方法。返回一个表示OUT参数参数索引的值的对象,如果支持该转换,则将从参数的SQL类型转换为请求的Java数据类型。如果不支持转换或为类型指定null,将抛出SQLException。如果不支持转换,则类型为空或发生其他错误。异常的getCause()方法可能会提供更详细的异常,例如,如果发生了转换错误。抛出异常SQLException。

    getObject(String parameterIndex, Class type)此方法与JDBC3.0中的getObject()方法有区别,此方法中第二个参数为泛型Class,为新增方法。与getObject(int parameterIndex, Class type)的区别是parameterIndex参数的类型,返回一个表示OUT参数参数名称值的对象,如果支持此转换,则将从参数的SQL类型转换为请求的Java数据类型。如果不支持转换或为类型指定null,将抛出SQLException。如果不支持转换,则类型为空或发生其他错误。异常的getCause() 方法可能会提供更详细的异常,例如,如果发生了转换错误。抛出异常 SQLException。

存储和检索 XML 文档

由 World Wide Web Consortium(W3C)定义的“可扩展置标语言”(XML)提供以文本、可编辑文件(称为 XML 文档)描述结构化数据的规则、指南和惯例。XML 仅使用定界数据条的标记,将对数据的解释留给使用它的应用程序来处理。XML 是一种以开放的、与平台无关的格式表示数据的方法。

将访问 XML 文档的当前可用的 API 称为 JAXP(“用于 XML 解析的 Java™ API”)。该 API 有下列两个子集:

  • “XML 的简单 API”(SAX)是事件驱动协议,带有编程人员提供的回调方法,当它分析文档时,XML 解析器调用这些方法。
  • “文档对象模型”(DOM)是随机访问协议,其将 XML 文档转换为内存中的对象集合,可由编程人员自主操纵它。DOM 对象有数据类型 Document。

JAXP 还包含 plugability layer,为了创建和配置 SAX 解析器并创建 DOM 对象,通过提供标准 factory 方法, 其实现对 SAX 和 DOM 编程访问的标准化。

对 JDBC API 的 GBase 8s 扩展促进对数据库列中 XML 数据的存储和检索。在数据存储期间使用的这些方法有助于解析 XML 数据,核实存储的 XML 数据的形式良好性和有效性,并确保拒收无效的 XML 数据。在数据检索期间使用的方法有助于将 XML 数据转换为 DOM 对象和类型InputSource,这是 SAX 和 DOM 方法的标准输入类型。在仍然提供关于编程人员使用哪个 JAXP 软件包的灵活性的同时,设计 GBase 8s 扩展来支持 XML 编程人员。

建立环境,来使用 XML 方法

本部分包含要准备系统来使用 JDBC 驱动程序 XML 方法所需要了解的信息。

设置 CLASSPATH

要使用 XML 方法,请将下列文件的路径名称添加至 CLASSPATH 设置:

  • gbasedbtjdbc_xx.jar
  • xerces.jar

此外,构建 gbasedbtjdbc_xx.jar 需要使用来自支持 SAX、DOM 和 JAXP 方法的 .jar 文件的代码。要使用 gbasedbtjdbc_xx.jar,必须将这些 .jar 文件添加至 CLASSPATH 设置。

JDK version 1.4 或更新的版本使用缺省的 XML 解析器,即使 xml4j 解析器在 CLASSPATH 中。要使用 SAX 解析器的 xml4j 实现,请在应用程序代码中设置下列系统属性,或使用 -D 命令行选项:

  • 必须将属性 javax.xml.parsers.SAXParserFactory 设置为 org.apache.xerces.jaxp.SAXParserFactoryImpl。
  • 对于“文档对象模型”,必须将属性 javax.xml.parsers.DocumentBuilderFactory 设置为org.apache.xerces.jaxp.DocumentBuilderFactoryImpl。

要获取关于如何设置这些属性的更多信息,请参阅 指定解析器 factory。

指定解析器 factory

在缺省情况下,xml4j xerces 解析器使用未经验证的 XML 解析器。要使用替代的 SAX 解析器 factory,请从命令行运行应用程序,如下:

% java -Djavax.xml.parsers.SAXParserFactory=new-factory

如果未从命令行运行,则必须将 factory 名称括在双引号中:

% java -Djavax.xml.parsers.SAXParserFactory="new-factory"

还可在代码中设置系统属性:

System.setProperty("javax.xml.parsers.SAXParserFactory", "new-factory")

在此代码中,new-factory 是替代的解析器 factory。例如,如果您正在使用 xerces 解析器,则以org.apache.xerces.jaxp.SAXParserFactoryImpl 来替代 new-factory。

还可能为 DOM 方法使用替代的文档 factory for DOM。请从命令行运行应用程序,如下:

% java -Djavax.xml.parsers.DocumentBuilderFactory=new-factory

如果未从命令行运行,则 factory 名称必须括在双引号中:

% java -Djavax.xml.parsers.DocumentBuilderFactory="new-factory"

还可在代码中设置系统属性:

System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "new-factory")

例如,如果正在使用 xerces 解析器,则以 jorg.apache.xerces.jaxp.DocumentBuilderFactoryImpl 来替代 new-factory。

插入数据

可使用本部分中的方法,来将 XML 数据插入至数据库列。

本部分中方法声明中的参数有下列含义:

  • file 参数是一 XML 文档。可通过 URL(诸如 http://server/file.xml 或 file:///path/file.xml)或路径名称(诸如 /tmp/file.xml 或c:\work\file.xml)来引用该文档。
  • handler 参数是您提供的可选类,包含 SAX 解析器作为它正在解析的文件的回调例程。如果未指定值,或如果将 handler 设置为 NULL,则驱动程序使用回显成功或失败的空回调例程(驱动程序以 SQLException 的形式报告失败)。
  • validating 参数告诉 SAX 解析器 factory 使用验证的解析器,而不是仅检查形式的解析器。

如果未指定 nsa 或 validating,则驱动程序使用 xml4j 未经验证的 XML 解析器。要更改缺省值,请参阅 指定解析器 factory。

  • nsa 参数告诉 SAX 解析器 factory,可否使用可处理命名空间的解析器。

下列方法通过使用 SAX 解析文件,并将它转换为一字符串。然后,可使用由这些方法返回的字符串作为 PreparedStatement.setString() 方法的输入,来将数据插入至数据库列内。

public String XMLtoString(String file, String handler, boolean
validating,boolean nsa) throws SQLException
public String XMLtoString(String file, String handler) throws
SQLException
public String XMLtoString(String file) throws SQLException

下列方法通过使用 SAX 来解析文件,并将它转换为类 InputStream 的对象。然后,可使用 InputStream 对象作为PreparedStatement.setAsciiStream()、PreparedStatement.setBinaryStream() 或 PreparedStatement.setObject() 方法的输入,来将数据插入至数据库列内。

public InputStream XMLtoInputStream(String file, String handler,
boolean validating,boolean nsa) throws SQLException;
public InputStream XMLtoInputStream(String file, String handler)
throws SQLException;
public InputStream XMLtoInputStream(String file) throws
SQLException;

要获取使用这些方法的示例,请参阅 插入数据示例。

如果未指定值,或如果将 handler 设置为 NULL,则驱动程序使用缺省的 GBase 8s 处理器。

重要

驱动程序截断对列来说过长的输入数据。例如,如果将 x.xml 文件插入至 char (55) 类型的类内,而不是 char (255) 类型的列,则驱动程序插入截断的文件,且不报错(然而,驱动程序抛出 SQLWarn 异常)。当选择截断的行时,解析器抛出 SAXParseException,因为该行包含无效的 XML。

检索数据

可使用本部分中的方法,来转换从数据库列访存了的 XML 数据。这些方法或者帮助您将选择了的 XML 文本转换为 DOM,或者帮助您以 SAX 来解析数据。InputSource 类是 JAXP 解析方法的输入类型。

要获取关于 file、handler、nsa 和 validating 参数的信息,请参阅 插入数据。

下列方法将 String 或 InputStream 类型的对象转换为 InputSource 类型的对象。可使用 ResultSet.getString()、ResultSet.getAsciiStream()或 ResultSet.getBinaryInputStream() 方法来从数据库列检索数据,然后,将检索的数据传至 getInputSource(),用于任何 SAX 或 DOM 解析方法。(要获取示例,请参阅 检索数据示例。)

public InputSource getInputSource(String s) throws SQLException;
public InputSource getInputSource(InputStream is) throws
SQLException;

下列方法将 String 或 InputStream 类型的对象转换为 Document 类型的对象:

public Document StringtoDOM(String s, String handler, boolean
validating,boolean nsa) throws SQLException
public Document StringtoDOM(String s, String handler) throws
SQLException
public Document StringtoDOM(String s) throws SQLException

public Document InputStreamtoDOM(String s, String handler, boolean
validating,boolean nsa) throws SQLException

public Document InputStreamtoDOM(String file, String handler)
throws SQLException
public Document InputStreamtoDOM(String file) throws SQLException

要获取使用这些方法的示例,请参阅 检索数据示例。

插入数据示例

本部分中的示例说明将 XML 文档转换为可接受插入至 GBase 8s 数据库列内的格式。

XMLtoString() 示例

下列示例将三个 XML 文档转换为字符串,然后,使用这些字符串作为 SQL INSERT 语句中的参数值:

PreparedStatement p = conn.prepareStatement("insert into tab values(?,?,?)");
p.setString(1, UtilXML.XMLtoString("/home/file1.xml"));
p.setString(2, UtilXML.XMLtoString("http://server/file2.xml");
p.setString(3, UtilXML.XMLtoString("file3.xml");

下列示例将一个 XML 文件插入至 LVARCHAR 列。在此示例中,tab1 是以 SQL 语句创建的表:

create table tab1 (col1 lvarchar);

代码为:

try
{
String cmd = "insert into tab1 values (?)";
PreparedStatement pstmt = conn.prepareStatement(cmd);
pstmt.setString(1, UtilXML.XMLtoString("/tmp/x.xml"));
pstmt.execute();
pstmt.close();
}
catch (SQLException e)
{
// Error handling
}

XMLtoInputStream() 示例

下列示例将一个 XML 文件插入至 text 列。在此示例中,以 SQL 语句来创建表 tab2:

create table tab2 (col1 text);

代码为:

try
{
String cmd = "insert into tab2 values (?)";
PreparedStatement pstmt = conn.prepareStatement(cmd);
pstmt.setAsciiStream(1, UtilXML.XMLtoInputStream("/tmp/x.xml"),
(int)(new File("/tmp/x.xml").length()));
pstmt.execute();
pstmt.close();
}
catch (SQLException e)
{
// Error handling
}

检索数据示例

下列示例展示从 GBase 8s 数据库列检索数据,以及将数据库转换为 XML 解析器可接受的格式。

StringtoDOM() 示例

此示例在 xmlcol 是包含 XML 数据的lvarchar类型列的假设之下操作。可以下列代码访存数据并转换为 DOM:

ResultSet r = stmt.executeQuery("select xmlcol from table where
...");
while (r.next()
{
Document doc= UtilXML.StringtoDOM(r.getString("xmlcol"));
// Process ‘doc'
}

InputStreamtoDOM() 示例

下列示例将 XML 数据从 text 列访存至 DOM 对象内:

try
{
String sql = "select col1 from tab2";
Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery(sql);
while(r.next())
{
Document doc = UtilXML.InputStreamtoDOM(r.getAsciiStream(1));
}
r.close();
}
catch (Exception e)
{
// Error handling
}

getInputSource() 示例

此示例检索存储在列xmlcol 中的 XML 数据,并将它转换为 InputSource 类型的对象;然后,可以任何 SAM 或 DOM 解析方法,来使用 InputSource 对象 i:

InputSource i = UtilXML.getInputSource
(resultset.getString("xmlcol"));

此示例使用 xerces.jar 中的 JAXP API 实现,来解析xmlcol列中访存了的 XML 数据:

InputSource input = UtilXML.getInputSource(resultset.getString("xmlcol"));
SAXParserFactory f = SAXParserFactory.newInstance();
SAXParser parser = f.newSAXParser();
parser.parse(input);

在下列示例中,tab1 是以 SQL 语句创建的表:

create table tab1 (col1 lvarchar);

下列示例将 XML 数据从 LVARCHAR 列检索至 InputSource对象内,用于解析。此示例通过调用 org.apache.xerces.parsers.SAXParser 处的解析器,来使用 SAX 解析。

try
{
String sql = "select col1 from tab1";
Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery(sql);
Parser p = ParserFactory.makeParser("org.apache.xerces.parsers.SAXParser");
while(r.next())
{
InputSource i = UtilXML.getInputSource(r.getString(1));
p.parse(i);
}
r.close();
}
catch (SQLException e)
{
// Error handling
}

下列示例将 XML 数据从 text 列访存至InputSource 对象内,用于解析。此示例与前一示例相同,但它使用 JAXP factory 方法,而不是 SAX 解析器来分析数据。

try
{
String sql = "select col1 from tab2";
Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery(sql);
SAXParserFactory factory = SAXParserFactory.newInstance();
Parser p = factory.newSAXParser();
while(r.next())
{
InputSource i = UtilXML.getInputSource(r.getAsciiStream(1));
p.parse(i);
}
r.close();
}
catch (Exception e)
{
// Error handling
}