中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> SUN专区 > Java技术 > J2EE
JDBCTM 2.0 基本原理(一)
作者:佚名 时间:2005-09-06 16:40 出处:互连网 责编:wqh21
              摘要:此教程是jGuru 最新提供的全面介绍JDBC基本概念的课程,包括API基本原理、Class如何工作、以及如何使用JDBC 2.0中的新功能。

JDBCTM入门

 

JDBCTM 是一种 Java TM (应用编程接口),它制定处理表格数据和常见的关系型数据 的标准框架。当 JDBC 2.0开始让程序员们了解 SQL 时,SQL 仍然是标准数据库 引擎的混合用语,它代表着将数据从代码中分离出来的重大行业成功。在介绍这 门课程本身之前,花点时间了解一些从 SQL 直接演变到 JDBC 的背景知识是值得 的。

SQL

 

SQL 是用于创建、操作、检查和管理关系型数据库的标准化语言。虽然本课程 提供了“SQL 初步”和“ SQL 资源”,但不会广泛地讲解 SQL。

不过,将介绍下列内容:

数据库本质上是表的“智能”容件。

表是由行组成的容件。

行(概念上)是由列组成的容件。

列是具有名称、类型和值的单个数据项目。

在开始复习此定义并了解其重要区别时,可以采用以下类比:数据库相当于文 件系统;表则相当于文件;行相当于记录或构件;列相当于域或变量。如果还不 熟悉这些术语,那么在继续学习本课程之前要复习一些编程知识,特别是“输入 /输出(I/O)”操作中的知识。

因为 SQL 是应用程序的专用语言,所以一个语句可以具有很多操作含义,可 以对整个数据集启动高级操作(如分类合并)。SQL 标准制定于 1992 年。以便 程序可以和大多数数据库系统通信,而无需更改 SQL 命令。不过,在发送 SQL 命令之前,必须连接到数据库;并且,每个数据库供应商都有不同的发送界面和 不同的 SQL 扩展。进入 ODBC。

ODBC

 

ODBC(Open Database Connectivity,开放式数据库连接性)是基于 C 语言 的界面,它指向基于 SQL 的数据库引擎,提供了与数据库通信以及访问数据库 元数据(元数据是关于数据库系统供应商与数据存储方式等等的信息)的一致性 界面。个别供应商会给他们特别的数据库管理系统提供特有的驱动程序或“桥路 器”。因此,有了 ODBC 和 SQL,就可以连接到数据库,并按标准方式进行操作。这就难怪尽管开始是 PC 标准的 ODBC ,现在已经几乎变成了行业标准。

虽然 SQL 非常适合于操作数据库,但其设计目的并非常规的应用程序语言; 相反,它是仅作为与数据库通信的工具而设计的。还需要一个更通用和更完整的 编程语言,来安排 SQL 语句和向数据库输入,并处理结果以供数据操作、视觉显 示或报表生成。令人遗憾的是,无法顺利地编写可以在多平台上运行的程序,即 使数据库连接性的标准化问题已经大部分得到了解决。例如,在 C++ 中编写数据 库客户程序时,要让它在另一个平台上运行可能必须全部重写客户程序。即, PC 版软件不能在 Macintosh 上运行。理由有两个。第一, C++ 作为语言不具有 可移植性,因为 C++ 的规定不彻底(例如,int 保留多少个字 节?)第二,也是更重要的,每个平台支持的库,如网络访问和 GUI(Graphical User Interface,图形用户界面)准则是各不相同的。进入 Java 编程语言和 JDBC。

JavaTM 编程语 言和 JDBC

 

编写正确且遵守规范的 Java 程序,可以无需重新编译就在任何启用 Java 技 术的平台上运行。Java 编程语言彻底地进行了规定。根据定义,启用 Java 技术 的平台必须支持已知的核心库。java.sql 包或 JDBC 就是这样的 一个库,它们可以视为 ODBC 的可移植版本,且其本身就是重大的标准。Java编 程语言和 JDBC 一起使用,可以给编写数据库应用程序提供正确的可移植性解决 方案。

注意: 虽然可移植的应用程序和标准数据库界面都是重大的成果,但不要 忘记,因为历史、竞争、有时是没有意义的原因,各种数据库并没有彻底地进行 标准化。这可能意味着,必须根据(甚至同一平台上的)特定数据库的性能或内 在的调整来寻找“最低公分母”。无论采用标准的 SQL、 ODBC、 JDBC、或其他 解决方案,都存在这个问题。

JDBC 驱动程序属于类,它实现 JDBC 驱动程序界面,并可以为特别的数据库 转换程序(一般是 SQL)请求。无疑,驱动程序在这里起了重要作用。驱动程序 类型有四种,“ JDBC 驱动程序类型”中的 JDK( Java Development Kit, Java 开发工具 箱)里对此进行了介绍。本课程采用第四类驱动程序,是因为它们有近乎零的安 装要求和富于变化的性质。就特别的项目而言,另一种驱动程序类型可能更有意 义。大多数的数据库供应商现在都提供驱动程序,以实现特定系统的 JDBC API。 这些通常都是免费提供的。第三方驱动程序也可以获得,成本从免费到费用浩大 的都有。到 JDBC 驱动程序资源的链接,请查看“专门信 息”和另一个资源

JDBC 1.0

 

JDBC 1.0 API 提供基本的数据访问准则,主要由以下界面和类组成:

驱动程序

DriverManager

连接

语句

PreparedStatement

CallableStatement

ResultSet

DatabaseMetaData

ResultSetMetaData

类型

 

如本课程所介绍的,要将“驱动程序”传递到 DriverManager, 然后获得“连接”。其次,创建语句、PreparedStatement、或 CallableStatement,并将它们用于更新数据库或执行查询。查询 返回包含有已请求数据的 ResultSet,该 ResultSet 是按“类型”检索的。DatabaseMetaDataResultSetMetaData 类可以用来提供有关数据库或 ResultSet 的信息。

 

JDBC 2.0

 

JDBC 2.0 API分为两个部分:即本课程将介绍的核心 API 和“ JDBC 2.0 可选包”。一般说来,JDBC 2.0 核心 API 添加了一些类,但主要 涉及性能、类增强和功能以及新的 SQL3(又名 SQL - 99)数据类型。

核心 API 中的新功能包括可卷动的结果集、批更新、编程性插入、删除、更 新、性能提示、国际化 Unicode 字符流的字符流、完全精确的 java.math.BigDecimal 值以及对值为“日期”“时间”以及“时间标示”的时区的支持。

当准备本课程的时候,JDBC 3.0草案正在考虑中,预计会出现在 JDK 的 1.4 版本中。

完整范例

 

本课程中的第一个 JDBC 实践经验是基本而完整的范例。该范例说明了有关创 建并访问数据库信息的全面概念。编写数据库应用程序时遇到的基本问题是:

创建数据库。数据库可以使用数据库供应商提供的工具创 建;或经由从 Java 程序提供给数据库的 SQL 语句创建。因为通常会有数据库管 理员(当然,可能是开发者您)负责,且并非全部的 JDBC 驱动程序都要通过 “数据定义语言”( Data Definition Language, DDL)来 支持数据库的建立,所以,本文大体上会专门介绍 DBMS ( DataBase Management System,数据库管理系统)和驱动程序。如果您对进一步的细节感兴 趣,可以参看典型的“创建数据库”语句;但务必复习 DBMS SQL参考,尽管它不 是 SQL 标准的构成,但却是由 DBMS 决定的。

连接数据库这是 JDBC 驱动程序最重要的工作,且必须向它传递特定信息。要 求的基本信息有“数据库 URL(统一资源定位符)”、“用户标识”和“密码”。 根据驱动程序的不同,可能还有很多其他的参数、属性或特性。这里有两个范例:

*Cloudscape*

数据库连接 URL 属性

*DB2*

AS/400 TM JDBC 特性

创建表。虽然数据库包含有表,但这些表都是包含数据的 实际的组件,形式是行列表单。表的创建由DDL CREATE TABLE 语句完 成。本语句有多种选项,各个供应商有些不同。再次强调遇到特殊情况时务必复 习 DBMS SQL 参考资料。

在数据库中插入信息。可以使用数据库的特殊工具添加和 维护数据,或用 SQL 语句以编程的方式发送出去。根据设计,本课程将集中介绍 通过 JDBC 将 SQL 语句发送到数据库。

有选择地检索信息。在发送 SQL 命令去检索数据,并使 用 JDBC 将结果变成变量后,程序代码就和任何其他变量一起显示或操作该数据。

方案描述

 

本范例的初始任务要求安装构件并插入数据,以跟踪 jGuru Jive Java Jumphouse 上的 Java (即咖啡)进入量,简称“ 4J 咖啡”。 然后,必须生成“ 4J 咖啡”的管理报告,包括咖啡总销售额以及顾客一天内消 费的最大咖啡量。数据如下:

jGuru Jive Java Jumphouse 中的咖 啡消费
“在 4J 咖啡中,咖啡因是我们最重要的产品”

 

项目顾客DOW类型
1 John 星期一 1 JustJoe
2 JS 星期一 1 Cappuccino
3 Marie 星期一 2 CaffeMocha
4 Anne 星期二 8 Cappuccino
5 Holley 星期二 2 MoJava
6 jDuke 星期二 3 Cappuccino
7 Marie 星期三 4 Espresso
8 JS 星期三 4 Latte
9 Alex 星期四 3 Cappuccino
10 James 星期四 1 Cappuccino
11 jDuke 星期四 4 JustJoe
12 JS 星期五 9 Espresso
13 John 星期五 3 Cappuccino
14 Beth 星期五 2 Cappuccino
15 jDuke 星期五 1 Latte

创建数据库

 

如前所述,数据库的创建是特定于 DBMS 的。为有助于了解范例,这里对遵 守 JDBC 标准的基本过程规则进行了例外处理。只需设置传递到驱动程序的数据 库连接的 URL 属性,就可以在 Cloudscape 中创建数据库。该属性的设置是: create=true. 在 DBMS 的默认目录中,就创建了已命名的数据库, 此处是 jGuru。对于“Cloudscape 安装和 设置”中介绍的 J2EE 下载,它将为 J2EE_HOME/Cloudscape。 如果数据库已经存在,Cloudscape 会创建“连接”,但另一方面会给出 SQLWarning

注意: 记住,这是 Cloudscape 的方法,不一定适用于任何其他的 DBMS。 例如,在 UDB2/NT 上创建数据库,就要使用 CREATE DATABASE jGuru。 在 DB2/400上,要首先给出 STRSQL 命令,然后使用“CREATE COLLECTION jGuru”。

连接数据库

 

使用 DriverManager 创建数据库连接有两个步骤。

装载 JDBC 驱动程序。

必须装载启用 JDBC 类的驱动程序,以和数据源通信。在初始范例中,与 Cloudscape 一起使用的驱动程序类, RmiJdbcDriver,是固定编 码的。动态装载驱动程序的标准方法如下:

Class.forName( DriverClassName);

标准的 JDBC CompliantTM驱动 程序也用本代码创建新的驱动程序类。令人遗憾的是,实际上不是所有情况都行 得通。因此,本练习使用以下代码:

Class.forName(DriverClassName).newInstance();

尽管多数情况下,本代码会创建额外的对象,但用于确定是否创建了对象实例 并在没有创建时创建新对象所要求的代码,通常超出新建的成本。好在废料收集 器最后会清理未引用的对象,而 DriverManager 不会将驱动程序 注册两次。

借助于 jdbc.drivers系统特性,也可以从命令行指定驱动程 序;但此方法要求在编译时间里,驱动程序要在类途径上。

java -Djdbc.drivers=DriverClassName AJavaApp

 

本课程中使用的连接到 Cloudscape 的特定 DriverClassName 的建议创建方 式是:

COM.cloudscape.core.RmiJdbcDriver

 

连接数据源

驱动程序提供创建“连接”的方法,但要求使用 jdbc 协议的特定的 URL 类 型。通用的表单是 jdbc:<subprotocol>:<subname>。更 多信息,请查看“ JDBC API 基础知识”中的“ 常规使用和 JDBC URL”。

人们经常认为理当如此的一个明显的观点是:使用 URL 意味着 JDBC 应用程 序会自动

jdbc:cloudscape:rmi:jGuru;create=true

在使用 DriverManager 类时,如果请求连接已传递 URL 的“连 接”,DriverManager 就会选择适当的驱动程序;这里,仅仅装载 了 Cloudscape 驱动程序。“连接”请求的标准形式如下:

Connection con = DriverManager.getConnection(
URL,
Username,
Password );

 

本形式具有最佳的可移植性,即使“用户名”和“密码”由于数据库默认或 ODBC 数据源的文本文件无法使用此类属性而为空字符串(""), 也是如此。

*Cloudscape*

就 Cloudscape 驱动程序而言,这是因‘create = true’URL 属性(随后连 接将去掉)创建数据库的实际所在。

创建表

 

虽然“连接”类有许多性能,但是为了使用 DDL 或“数据操作语言”(Data Manipulation Language,DML)SQL 语句,仍要求“语句”对象。所以,下一步 是向“连接”要求“语句”对象:

Statement stmt = con.createStatement();
此时,程序可以开始起一点实际作用了。为了存储数据,范例在 jGuru 数据库中 创建了命名为 JJJJData 的表。下面是该 SQL 语句,包括每个数 据项需要的列。为清晰起见,范例中的 SQL 关键字都是大写,但这根据程序员的 爱好而定,并非必需如此。

 

CREATE TABLE JJJJData (
Entry      INTEGER      NOT NULL,
Customer   VARCHAR (20) NOT NULL,
DOW        VARCHAR (3)  NOT NULL,
Cups       INTEGER      NOT NULL,
Type       VARCHAR (10) NOT NULL,
PRIMARY KEY( Entry )
)
其程序代码是:
  stmt.executeUpdate( "CREATE TABLE JJJJData ("  +
"Entry      INTEGER      NOT NULL, "    +
"Customer   VARCHAR (20) NOT NULL, "    +
"DOW        VARCHAR (3)  NOT NULL, "    +
"Cups       INTEGER      NOT NULL, "    +
"Type       VARCHAR (10) NOT NULL,"     +
"PRIMARY KEY( Entry )"                  +
")" );
注意,实际的 SQL语句没有终结符。不同的数据库使用不同的终结符,代码列表 中为了可移植性没有使用终结符。相反,将插入适当终结符的任务交给了驱动程 序。

 

该代码还对数据库表明,没有“零值”列,这主要是为了避免给 SQL 新手带 来困扰。为了识别每行,代码定义了主键。

在数据库中插入信息

 

表创建后,就可以使用 SQL 的 INSERT 语句添加数据了:

INSERT INTO JJJJData VALUES ( 1, 'John', 'Mon', 1, 'JustJoe' )
INSERT INTO JJJJData VALUES ( 2, 'JS',   'Mon', 1, 'Cappuccino' )
INSERT INTO JJJJData VALUES ( 3, 'Marie', 'Mon', 2, 'CaffeMocha' )
...
在程序范例中,命名为 SQLData的阵列包含有实测值,每个元素的 形式类似于:
"(1,  'John',   'Mon', 1, 'JustJoe')"
The program code corresponding to the INSERT statements above is:
 stmt.executeUpdate(
"INSERT INTO JJJJData VALUES " + SQLData[i] );

 

循序渐进

 

简短地复习一下迄今为止学习的内容:首先,任何 JDBC 程序会装载 JDBC 驱 动程序,并使用 jdbc 协议(包括此处创建数据库的属性)创建 URL 。此时,程序可以连接到数据库。其次,向返回的“连接”对象请求“语句”。 本节专门范例将使用传递给驱动程序的 SQL 语句创建并填充 JJJJData表。

本节的练习包括创建 JJJJData 表和插入要求行的完整应用程序的源代码。

练习

 

  1. 创建并填充表

检索数据库中的信息

 

要从数据库检索信息,可借助于 Statement.executeQuery 方法向数据库发送 SQL SELECT 语句,该语句以数据行的形式返回 ResultSet 对象中的要求信息。默认的 ResultSet 会逐行使用 ResultSet.next() (定位到下一行)和 ResultSet.getXXX() 进行检查, 以获得各列的数据。

例如,如何获得 4J Cafe 顾客一天内消费的最大咖啡数量(杯)。根据 SQL, 获取最大值的方法之一是使用“订购者”从句按“杯”列对表进行降序排序。返 回的 ResultSet 中的首行就是最大数量(杯)。全部列都会被选 中,以便程序按预期报告和检验添加到表中的数据。SQL 语句如下:

SELECT Entry, Customer, DOW, Cups, Type
FROM JJJJData
ORDER BY Cups DESC
在程序中,用下列方式执行 SQL 语句:
      ResultSet result = stmt.executeQuery(
"SELECT Entry, Customer, DOW, Cups, Type " +
"FROM JJJJData " +
"ORDER BY Cups DESC");

 

数据导航

 

如果存在下一行,ResultSet.next() 会返回布尔值:true;否 则返回 false(表示已经到达数据/集合的末尾)。 原则上,获得 ResultSet 时,指针或光标刚好定位在第一行之前。调用 next() 会移到第一 行,然后是第二行等等。为了获取第一行,即杯数最大的行,可进行一些特别处 理:

if( result.next() )
if 语句收集数据。然后,采用
while(result.next())
循环,以允许程序持续到数据的末尾。

 

Data Extraction

 

数据提取一旦定位在行上,应用程序就可以使用适当的 ResultSet.getXXX 方法逐列获取数据。下面是范例中用于收集数据的方法,以及为每行汇总杯列的 代码。

          iEntry = result.getInt("Entry");
Customer = result.getString("Customer");
DOW = result.getString("DOW");
Cups = result.getInt("Cups");
TotalCups += Cups;  // increment total
Type = result.getString("Type");

 

程序对 System.out.println() 使用报告标准。

如果运行顺利,会显示下列结果:

JS consumed the most coffee, 9 Espressos on Friday!

The total cups of coffee consumed was 48.

The row by row output is:

12 JS Fri 9 Espresso
4 Anne Tue 8 Cappuccino
11 jDuke Thu 4 JustJoe
8 JS Wed 4 Latte
7 Marie Wed 4 Espresso
13 John Fri 3 Cappuccino
9 Alex Thu 3 Cappuccino
6 jDuke Tue 3 Cappuccino
14 Beth Fri 2 Cappuccino
5 Holley Tue 2 MoJava
3 Marie Mon 2 CaffeMocha
15 jDuke Fri 1 Latte
10 James Thu 1 Cappuccino
2 JS Mon 1 Cappuccino
1 John Mon 1 JustJoe

 

注意, ResultSet 只按“杯”的次序排列。因此,很难保 证杯数相同项目的次序。例如,都是3杯的 John、Alex 和 jDuke 项目可能以 任何次序出现。这 3 个项目将在 4 杯或 4 杯以上项目之后,在 2 杯或 2 杯以 下的项目之后(记住,是按降序排列),实际上,也只能做到这些。

本节的练习包括检查 JJJJData表和生成报告的 完整应用程序的源代码。

练习

 

  1. 数据检索

 

本节结束时,要记住:

JDBC 具有可移植性。

为简单起见,此处的驱动程序名称、URL、用户和密码已经进行了固定编码。 用变量替代此信息后,这些程序将以任何 JDBC Compliant 驱动程序运行。

本节所有代码和材料适用于并运行于带有适当驱动程序的 JDK 1.1 和 JDBC 1.2。

不过,在这一点上,本课程假定可以使用 JDK 1.3 和 JDBC 2.0(但大多数 材料在 JDK 1.2 之下也可以顺利运行)。

连接 Java 程序和数据库

 

连接”对象代表并控制到数据库的连接。“连接数据 库”中已经介绍了连接的基本知识;本节将澄清几个要点,介绍“连接”控制 的不同区域,并给出两个练习来示范提供顺利连接所需信息的一般方法。

虽然 JDBC 中的一切都取决于数据库和 JDBC 驱动程序的功能,但一般说来, 可以有多个方法连接到相同的数据库和/或“连接”到多个数据库。DriverManager 类处理驱动程序注册,并提供获取“连接”的方法。注意,全部 DriverManager 方法都是静态的;此处不举例说明。

获取“连接”的第一步常常最难:即,如何创建@_#_$!!!@_#_ database URL? 如上所述,在用<subprotocol>:识别机器或服务器以及<subname>基 本上用来识别数据库时,基本代码jdbc:<subprotocol>:<subname> 显得非常精炼。实际上,其内容取决于专用驱动程序,并会因为产生“没有合适 的驱动程序”的错误等类途径问题使人不知所措,倍受困扰。以上述的范例中使 用的 Cloudscape URL 为例:

jdbc:cloudscape:rmi:jGuru
上述代码会解译成
jdbc:    <subprotocol>:      <subname>
jdbc:     cloudscape:rmi:     jGuru
这个相当简单,主要是因为客户程序且服务器都在相同的机器上运行。在低于第 四种类型的驱动程序中常常见到类似的 URL,因为要涉及到另外的设置,且定位 服务器要求的信息要从设置信息处获得。

 

即使在这里,情况并不总是令人满意。支持远程(并且甚至当地)连接的大多 数 DBMS 引擎,都使用TCP / IP(传输控制协议/ Internet协议)端口来做到 这一点。事实上,即使 Cloudscape 也在启动后使用cloudscape:rmi: subprotocol; run netstat,并可以在 1099 端口上看到。像任何 其他的套接字程序一样,DBMS 引擎可以随意确定要使用的端口。除了通常使用 的 TCP/IP 标准外,也可以使用其他的通信协议。例如, DB2 就可以在几个平 台上使用 APPC (Advanced Program to Program Communication,先进的程序 间通讯)。

在应用程序试着连接网络或 Internet 服务器时,必须提供识别/存储单元信 息。常见的 JDBC 方法是使用//host:port/subsubname,这里的主 机是 IP 地址或 DNS ( Domain Name Service,域名服务)或其他的可定位名 称。在驱动程序/数据库文档里查找默认端口,且记住系统管理员有权决定使用 不同的端口。这里的数据库就是 subsubname,而驱动程序的编写者可以随意在 他们自己的句法中添加其他属性。再次使用 Cloudscape 为例,该代码用来创建 数据库:

jdbc:cloudscape:rmi:jGuru;create=true
;create=true部分是使用 Cloudscape 句法的属性。含义是:在文档 中,检查出驱动程序和数据库。

 

“连接”在收集无用数据时自动关闭,但审慎的程序员会始终明确地关闭“连 接”以直接地确保节省资源。注意,虽然 API 会明确地表示关闭“连接”以“立 即释放数据库和 JDBC 资源”,但 JDBC 会建议关闭“连接”和“语句”。

和其他 JDBC API 的重要区域一样,“连接”也是界面。很多的程序员想 知道对象的起源处,因为界面不能用具体事例来予以说明。扼要的答案是: JDBC 驱动程序实现了界面并在请求时返回实际对象。 这同时说明了为什么应用程序编 译时十分完整,运行时却问题成堆:因为代码是参照标准接口编译的,只有装载 并运行程序和驱动程序时才能得到实际的效果。

“连接”界面控制的区域

 

前面的大多数章节都介绍了 DriverManagergetConnection() 方法的设置。“连接”本身负责的区域包括:

创建“语句”、 PreparedStatementCallableStatement (和存储过程一起使用)实例。

获取 DatabaseMetadata 对象。

通过 commit()rollback() 方法控制事务。

设置事务涉及的隔离级别。

在给定数据库的本地非标准语言中,甚至有获取任何 SQL 语句的方法,该方 法的适当名称是 nativeSQL()。本课程随后的部分会介绍这些区 域。

 

在继续介绍前,先讲解“ JDBC 2.0 可选包”引进的新 DataSource 类。该规范说明建议将 DataSource 用作获取“连接”的方法,并 实际上提到了反对当前的 DriverManager/Connection 方法。虽 然 JDBC 程序员应该知道这点,甚至可能也在大多数 J2EE 环境中使用---但令 人惊奇的是 DriverManager 方法不久就被废弃了。

连接信息概述

 

从上面获取“连接”对象所需信息的介绍中可知,对信息进行固定编码不是个 令人满意的决定。以下练习给出了在两个通用的编程方案中获取该信息的两种方 法---即使用 ResourceBundle 和/或直接从最终用户处获取。

Cloudscape

 

您可能想知道,练习中给登录名和密码设置的“sa”和“admin”是 Cloudscape 的默认值还是胡乱设置的。答案是,在逻辑框以外,没有启用 Cloudscape 的验证/安全。必须亲自对它进行设置。否则,它就会忽视这些无效 参数和属性。从一开始,就已经引入了这些有效的虚拟名称,以介绍 JDBC 标准 “连接”参数。这再次强调了检查驱动程序和数据库文档的重要性。第二个答案 是,如同在很多其他区域中一样,编程时可能有镜像,但没有什么魔法。

练习

 

  1. 连接信息概述---批处理
  2. 连接信息概述---交互e

语句、ResultSets 以及与数据库的互动

 

语 句”对象是发送/执行(常规) SQL语句,并通过相关“连接”检索结果的容 件或传输机制。“连接界面控制的区域”中曾经介 绍,语句类型有三种,包括 Prepared StatementsCallable Statements,两者都是“语句”的子界面。 如前所述,无需创建新的“语句”实例,而是请求相关的“连接”进行创建:

Statement stmt = con.createStatement();

 

execute 系列是“语句”方法最常使用的:

executeQuery() 用来执行返回单个 ResultSet 的 SQL 语句。

executeUpdate()用来执行修改表或表中列值的 SQL 语句,并返回 修改过的行数(在 DDL 语句中为零)。

execute() 可用于执行任何类型的 SQL语句,但更针对那些可以返 回多个结果或值的 SQL语句。本课程不深入介绍该语句。

 

为了更灵活地使用不同的数据库和数据源, JDBC 没有限制语句可以发送的 SQL 语句种类。实际上,只要数据源可以识别(这是程序员的责任了),语句甚 至无需是 SQL 语句,这就带来了一些令人感兴趣的可能性。不过,标明为 JDBC Compliant 的驱动程序必须至少支持 ANSI SQL-92 Entry Level 的性能。

在“连接”收集无用数据时,语句将自动地关闭,但在不再需要时应该亲自关 闭。JDBC 建议始终明确地关闭该“语句”。

修改数据

 

更新对程序员来说有特别的含义,甚至对 SQL 也是如此。所以,对于用来执 行 DML(INSERTUPDATEDELETE) 语句、DDL 语句(如 CREATE TABLEDROP TABLEALTER TABLE 语句)的方法来说,executeUpdate() 大概不太受人欢迎。无论如何,它用于所有这些方面;实际上,根据经验,它应 用于不返回 ResultSet 的任何语句。

JDBC 对类型进行定义以匹配 SQL 数据类型。这些定义必须适合于数据,以避 免出现技术问题、意外结果,并能促进工作效率。可用和合适类型的更详尽信息, 请查看“Java- SQL 类型等效性”。

executeUpdate() 返回 int 值,它包含 INSERT、 UPDATE 或 DELETE 语句作用过的行数,或不返回任何东西的 SQL 语句(如 DDL 语句)的零。

练习

 

  1. 使用 executeUpdate()

数据库查询

 

executeQuery() 应用于返回 ResultSet 的“语句”,基本上是 SELECT 语句。

executeQuery()返回的默认 ResultSet 对象拥 有只向前移动的光标,该光标使用 next() 方法。应该注意, executeQuery()始终返回非空的 ResultSet。新手 常常比较 ResultSet 和零值,以确定是否已返回行。如果没有驱 动程序错误,就决不会出现这类情况。 next() 返回布尔值,在 另一行生效时是 true;在 ResultSet 耗尽时为 false。如果只希望返回单行,就可以使用 if 语 句。否则,通常使用 while 循环:

int iCount = 0;
while( myResultSet.next() )
{
// retrieve column data
// do something with it
iCount++;
}
if( iCount == 0 )
{
System.out.println(
"myResultSet returned no data.");
}
else
if( bNoErrorsOrExceptionsOrEarlyTerminations )
{
System.out.println(
"All rows from myResultSet were processed.");
}

 

应该按从左到右的语句(次序和 SELECT 中的相同)次序进行读 取列,并可以按列名称或索引获取列。尽管列名可能更易于理解,但使用索引更 有效率(按 1,2,3 而非 0,1,2,3...的索引顺序)。数据库和驱动程序都可能变 化,如果没有可移植性,在默认的 ResultSet 中可能一次仅仅只 能获取一行甚至是该行中的一列。

ResultSetgetXXX() 方法用来检索列数据。JDBC 对类型进行定义,以和 SQL数据类型匹配,每个数据类型都有 getXXX() 方法。可用类型和合适类型的更详尽信息,请查看“Java-SQL类 型等效性”。

“语句”一次仅仅打开一个 ResultSet,常常对新建数据重复 使用相同的 ResultSet。应该确保从 ResultSet 中 获取全部所需数据,再通过相关的“语句”执行另一个查询。在重复执行和 Statement.close() 时,“语句”应该自动地关闭 ResultSet, 但在不再需要数据时可以亲自关闭 ResultSet。审慎的程序员可能 始终明确地关闭 ResultSet

ResultSet 也可以返回元数据,它是有关 ResultSet 本身和所包含数据的信息。在“ ResultSet 元数据” 将更进一步地对此进行介绍。

练习

 

  1. 选择数据和显示信息

筹备语句

 

PreparedStatement 是“语句”的子界面,有以下好处:

已包含的 SQL 会被发送到数据库,并预先进行编译或筹备。由此开始发送已 筹备的 SQL,本步骤会被省略。更有活力的“语句”对每个执行都要求本步骤。 根据 DB 引擎的不同,SQL 可能会进行高速缓存并重复使用。即使对不同的 PreparedStatement 也是如此,并且大部分工作由 DB 引擎而不是 驱动程序完成。

PreparedStatement 可以处理列值的 IN 参数, 该参数的作用非常类似于方法的参数。

例如,PreparedStatement 能处理直接运行很易于出错的数据 变换,这些数据变换是迅速地在 SQL 上创建的;并以一种对开发者来说透明的方 式处理引用和日期。

 

注意: SQL3 类型通常假设使用 DML 的筹备语句。

这里,有两个安装和获取筹备语句的范例:

pstmtU = con.prepareStatement(
"UPDATE myTable SET myStringColumn = ? " +
"WHERE myIntColumn = ?"  );
pstmtQ = con.prepareStatement(
"SELECT myStringColumn FROM myTable " +
"WHERE myIntColumn = ? ");

 

问号,也被称作参数标志,是在语句执行前待设置的值。从 1 开始,按从左 到右的数字顺序对它们进行引用。PreparedStatementsetXXX() 方法用来设置 IN 参数,在进行更改前会保持所作设置。可用类型 和合适类型的更详尽信息,请查看“Java- SQL 类型等效性”。 下面是在上述语句中设置参数的范例:

pstmtU.setString( 1, "myString" );
pstmtU.setInt( 2, 1024 );
pstmtU.executeUpdate();
pstmtQ.setInt( 1, 1024 );
pstmtQ.executeQuery();

 

也可以筹备没有参数的语句。注意, PreparedStatement 拥有 自己的 execute 方法系列版本,它由于要设置参数所以没有自变 数。记住, PreparedStatement 是从“语句”继承下来的,并包 括了“语句”所有的功能。一般而言,在查询运行了多次仅有相同列的值发生变 化或重复运行同一查询时,请考虑使用筹备语句。

练习

 

  1. 使用筹备"语句"

 

Java - SQL类型等效性

 

JDBC 的" 类型"定义为转换成标准 Java 类型,提供了属类的 SQL 类型。通常是直接 确定所需的类型和方法。以下两个表显示用于获取每个数据类型的常规 ResultSet 方法。典型 setxxx() 方法的格式相同。

通用的 SQL 类型---标准检索方法

 

SQL 类型Java方法
BIGINT getLong()
BINARY getBytes()
BIT getBoolean()
CHAR getString()
DATE getDate()
DECIMAL getBigDecimal()
DOUBLE getDouble()
FLOAT getDouble()
INTEGER getInt()
LONGVARBINARY getBytes()
LONGVARCHAR getString()
NUMERIC getBigDecimal()
OTHER getObject()
REAL getFloat()
SMALLINT getShort()
TIME getTime()
TIMESTAMP getTimestamp()
TINYINT getByte()
VARBINARY getBytes()
VARCHAR getString()

为了显示, ResultSet.getString() 也可以应用于上述类型, 可能对 OTHER 例外。

 

SQL3 类型---检索方法

 

SQL 类型Java 方法
ARRAY getArray()
BLOB getBlob()
CLOB getClob()
DISTINCT getUnderlyingType()
REF getRef()
STRUCT (castToStruct)getObject()
JAVA_OBJECT (castToObjectType)getObject()

ResultSet.getObject() 也可以用于两个表中列出的任何类型。

这些看起来非常清晰明了,难度也不大,但专业程序设计员应该花些时间阅读 映射 Java 的 SQL 数据类型和映射 SQL 及 Java "类型"。尤其要通过" ResultSet.getXXX() 方法"检查"转换"表,以查看可用选项的种类。

对于应用定位程序的 SQL3 类型,因为文档上令 人遗憾的缺陷,人们常常对它发出这样的疑问:"开始时,该如何将类型输入数据 库呢?"最好的答案是,检查它们对应的类(例如, BLOBBlob 类),并根据 getXXX() 方法找出 setXXX() 方法应用的具体化数据,通常带有 PreparedStatement。就 Blob 而言是 getBinaryStream()getBytes(),因此对应地就 有了 setBinaryStream()setBytes()。更多的 信息和范例代码,请查看 LOB 和本部分相关的练习。

JDBC 例外类型以及例外处理

 

"我再不愿意想这件事情。"---一般而言,实话实说的开发者对问到例外/错误 处理时的反应很可能就是这句话。它说明了很难正确地进行处理,还常常会吃力 不讨好。这对于编制优质的应用程序也很关键。

本课程中的练习突出强调专门的 JDBC 区域,未对生产质量提出要求。同时, 从第一个练习开始介绍了异常处理的标准。不过,标准并不完整,因此介绍了三 种 SQLExceptions 以作弥补。

注意,加入 JDBC 2.0 中的第四种类型,BatchUpdateException, 在"批更新装置"中介绍。

SQL 例外

 

java.sql包中的许多方法都会形成 SQLException,它和任何其他"例外"一样要求尝试/捕捉语句块。其 目的是描述数据库或驱动程序错误(例如,SQL 语法)。除了从 Throwable 继承下来的标准 getMessage()SQLException 还 有两种提供详细资料的方法:一种方法是获取(或链接)其他的例外,一种方法 是设置其他的例外。

getSQLState()返回基于 X/ Open SQL 规范说明的 SQLState 标识符。这些会在 DBMS 手册中列出,或在"资源"中 寻找 SQLStates 的信息。

getErrorCode() 用来检索特定于供应商的错误代码。

getNextException() 检索下一个 SQLException, 或在没有 SQLException时为零值。程序和数据库间很多的情况都 可能出错。本方法允许跟踪全部发生的问题。

setNextException() 允许程序员给链添加 SQLException

 

这些方法应该相当直接了当。典型的捕捉代码看起来如下所示:

    try
{
// some DB work
} // end try
catch (  SQLException SQLe)
{
while( SQLe != null)
{
// do handling
SQLe = SQLe.getNextException();
}
} // end catch

 

提示: 程序员常常被语法错误弄得迷惑不解,这些语法错误似乎参 考一些无形的操作,如"ungrok found at line 1, position 14."不断地报告异 常处理程序中Connection.nativeSQL(yourQueryString)的输出量将会澄清事 实。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有