73.JAVA编程思想——JDBC

73.JAVA编程思想——JDBC

据估算,将近一半的软件开发都要涉及客户(机)/服务器方面的操作。Java 为自己保证的一项出色能力就是构建与平台无关的客户机/服务器数据库应用。在Java1.1 中,这一保证通过Java 数据库连接(JDBC)实现了。

数据库最主要的一个问题就是各家公司之间的规格大战。确实存在一种“标准”数据库语言,即“结构查询语言”(SQL-92),但通常都必须确切知道自己要和哪家数据库公司打交道,否则极易出问题,尽管存在所谓的“标准”。JDBC 是面向“与平台无关”设计的,所以在编程的时候不必关心自己要使用的是什么数据库产品。然而,从JDBC 里仍有可能发出对某些数据库公司专用功能的调用,所以仍然不可任性妄为。

和Java 中的许多API 一样,JDBC也做到了尽量的简化。我们发出的方法调用对应于从数据库收集数据时想当然的做法:同数据库连接,创建一个语句并执行查询,然后处理结果集。为实现这一“与平台无关”的特点,JDBC 为我们提供了一个“驱动程序管理器”,它能动态维护数据库查询所需的所有驱动程序对象。所以假如要连接由三家公司开发的不同种类的数据库,就需要三个单独的驱动程序对象。驱动程序对象会在装载时由“驱动程序管理器”自动注册,并可用Class.forName()强行装载。

为打开一个数据库,必须创建一个“数据库URL”,它要指定下述三方面的内容:

(1) 用“jdbc”指出要使用JDBC。

(2) “子协议”:驱动程序的名字或者一种数据库连接机制的名称。由于JDBC 的设计从ODBC 吸收了许多灵感,所以可以选用的第一种子协议就是“jdbc -odbc 桥”,它用“odbc”关键字即可指定。

(3) 数据库标识符:随使用的数据库驱动程序的不同而变化,但一般都提供了一个比较符合逻辑的名称,由数据库管理软件映射(对应)到保存了数据表的一个物理目录。为使自己的数据库标识符具有任何含义,必须用自己的数据库管理软件为自己喜欢的名字注册(注册的具体过程又随运行平台的不同而变化)。

所有这些信息都统一编译到一个字串里,即“数据库URL”。举个例子来说,若想通过ODBC 子协议同一个标识为“people”的数据库连接,相应的数据库URL 可设为:

String dbUrl ="jdbc:odbc:people"

如果通过一个网络连接,数据库URL 也需要包含对远程机器进行标识的信息。

准备好同数据库连接后,可调用静态方法DriverManager.getConnection(),将数据库的URL 以及进入那个数据库所需的用户名密码传递给它。得到的返回结果是一个Connection对象,利用它即可查询和操纵数据库。

下面这个例子将打开一个联络信息数据库,并根据命令行提供的参数查询一个人的姓(Last Name)。它只选择那些有E-mail 地址的人的名字,然后列印出符合查询条件的所有人:

1     代码

import java.sql.*;

public
class
Lookup {

public
staticvoid
main(String[]
args){

String dbUrl =
"jdbc:odbc:people";

String user =
"";

String password =
"";

try {

// Load the driver (registers itself)

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Connection
c = DriverManager.getConnection(dbUrl,
user, password);

Statement
s = c.createStatement();

// SQL code:

ResultSet
r = s.executeQuery("SELECT FIRST, LAST, EMAIL" +
"FROMpeople.csv people " +
"WHERE "+ "(LAST=‘"

+
args[0] + "‘) " +
" AND (EMAIL Is Not Null) " + "ORDER BY FIRST");

while (r.next()) {

// Capitalization doesn‘t matter:

System.out.println(r.getString("Last")+
", "+ r.getString("fIRST")+
": "+ r.getString("EMAIL"));

}

s.close();
// Also closes ResultSet

} catch (Exception
e) {

e.printStackTrace();

}

}

} /// :~

可以看到,数据库URL 的创建过程与我们前面讲述的完全一样。在该例中,数据库未设密码保护,所以用户名和密码都是空串。用DriverManager.getConnection()建好连接后,接下来可根据结果Connection对象创建一个Statement(语句)对象,这是用createStatement()方法实现的。根据结果Statement,我们可调用executeQuery(),向其传递包含了SQL-92 标准SQL 语句的一个字串(不久就会看到如何自动创建这类语句,所以没必要在这里知道关于SQL
更多的东西)。

executeQuery()方法会返回一个ResultSet(结果集)对象,它与继承器非常相似:next()方法将继承器移至语句中的下一条记录;如果已抵达结果集的末尾,则返回null。我们肯定能从executeQuery()返回一个ResultSet 对象,即使查询结果是个空集(也就是说,不会产生一个违例)。注意在试图读取任何记录数据之前,都必须调用一次next()。若结果集为空,那么对next()的这个首次调用就会返回false。对于结果集中的每条记录,都可将字段名作为字串使用(当然还有其他方法),从而选择不同的字段。另外要注意的是字段名的大小写是无关紧要的——SQL
数据库不在乎这个问题。为决定返回的类型,可调用getString(),getFloat()等等。到这个时候,我们已经用Java 的原始格式得到了自己的数据库数据,接下去可用Java 代码做自己想做的任何事情了。

2     让示例运行起来

就JDBC 来说,代码本身是很容易理解的。最令人迷惑的部分是如何使它在自己特定的系统上运行起来。之所以会感到迷惑,是由于它要求我们掌握如何才能使JDBC 驱动程序正确装载,以及如何用我们的数据库管理软件来设置一个数据库。

当然,具体的操作过程在不同的机器上也会有所区别。但这儿提供的在32 位Windows 环境下操作过程可有效帮助大家理解在其他平台上的操作。

1. 步骤1:寻找JDBC 驱动程序

上述程序包含了下面这条语句:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

这似乎暗示着一个目录结构,但大家不要被它蒙骗了。在我手上这个JDK1.1 安装版本中,根本不存在叫作JdbcOdbcDriver.class 的一个文件。所以假如在看了这个例子后去寻找它,那么必然会徒劳而返。另一些人提供的例子使用的是一个假名字,如“myDriver.ClassName”,但人们从字面上得不到任何帮助。事实上,上述用于装载jdbc-odbc 驱动程序(实际是与JDK 1.1 配套提供的唯一驱动)的语句在联机文档的多处地方均有出现(特别是在一个标记为“JDBC-ODBC
Bridge Driver”的页内)。若上面的装载语句不能工作,那么它的名字可能已随着Java 新版本的发布而改变了;此时应到联机文档里寻找新的表述方式。

若装载语句出错,会在这个时候得到一个违例。为了检验驱动程序装载语句是不是能正常工作,请将该语句后面直到catch 从句之间的代码暂时设为注释。如果程序运行时未出现违例,表明驱动程序的装载是正确的。

2. 步骤2:配置数据库

同样地,我们只限于在32 位Windows 环境中工作;您可能需要研究一下自己的操作系统,找出适合自己平台的配置方法。

首先打开控制面板。其中可能有两个图标都含有“ODBC”字样,必须选择那个“32 位ODBC ”,因为另一个是为了保持与16 位软件的向后兼容而设置的,和JDBC 混用没有任何结果。双击“32 位ODBC ”图标后,看到的应该是一个卡片式对话框,上面一排有多个卡片标签,其中包括“用户DSN”、“系统DSN”、“文件DSN”等等。其中,“DSN”代表“数据源名称”(Data Source Name)。它们都与JDBC-ODBC 桥有关,但设置数据库时唯一重要的地方“系统DSN”。尽管如此,由于需要测试自己的配置以及创建查询,所以也需要在“文件DSN”中设置自己的数据库。这样便可让Microsoft
Query 工具(与Microsoft Office 配套提供)正确地找到数据库。注意一些软件公司也设计了自己的查询工具。

最有趣的数据库是我们已经使用过的一个。标准ODBC 支持多种文件格式,其中包括由不同公司专用的一些格式,如dBASE。然而,它也包括了简单的“逗号分隔ASCII”格式,它几乎是每种数据工具都能够生成的。就目前的例子来说,我只选择自己的“people”数据库。这是我多年来一直在维护的一个数据库,中间使用了各种联络管理工具。我把它导出成为一个逗号分隔的ASCII 文件(一般有个.csv 扩展名,用OutlookExpress 导出通信簿时亦可选用同样的文件格式)。在“文件DSN”区域,我按下“添加”按钮,选择用于控制逗号分隔ASCII
文件的文本驱动程序(Micr osoft Text Driver),然后撤消对“使用当前目录”的选择,以便导出数据文件时可以自行指定目录。

大家会注意到在进行这些工作的时候,并没有实际指定一个文件,只是一个目录。那是因为数据库通常是由某个目录下的一系列文件构成的(尽管也可能采用其他形式)。每个文件一般都包含了单个“数据表”,而且SQL 语句可以产生从数据库中多个表摘取出来的结果(这叫作“联合”,或者join )只包含了单张表的数据库(就象目前这个)通常叫作“平面文件数据库”。对于大多数问题,如果已经超过了简单的数据存储与获取力所能及的范围,那么必须使用多个数据表。通过“联合”,从而获得希望的结果。我们把这些叫作“关系型”数据库。

3. 步骤3:测试配置

为了对配置进行测试,需用一种方式核实数据库是否可由查询它的一个程序“见到”。当然,可以简单地运行上述的JDBC 示范程序,并加入下述语句:

Connection c =DriverManager.getConnection(

dbUrl, user, password);

若掷出一个违例,表明你的配置有误。然而,此时很有必要使用一个自动化的查询生成工具。我使用的是与Microsoft Office 配套提供的Microsoft Query,但你完全可以自行选择一个。查询工具必须知道数据库在什么地方,而Microsoft Query要求我进入ODBC Administrator 的“文件DSN”卡片,并在那里新添一个条目。同样指定文本驱动程序以及保存数据库的目录。虽然可将这个条目命名为自己喜欢的任何东西,但最好还是使用与“系统DSN”中相同的名字。做完这些工作后,再用查询工具创建一个新查询时,便会发现自己的数据库可以使用了。

4. 步骤4:建立自己的SQL 查询

我用Microsoft Query 创建的查询不仅指出目标数据库存在且次序良好,也会自动生成SQL 代码,以便将其插入我自己的Java 程序。我希望这个查询能够检查记录中是否存在与启动Java 程序时在命令行键入的相同的“姓”(Last Name)。所以作为一个起点,我搜索自己的姓“Eckel”。另外,我希望只显示出有对应Email地址的那些名字。创建这个查询的步骤如下:

(1) 启动一个新查询,并使用查询向导(Query Wizard)。选择“people”数据库(等价于用适应的数据库

URL 打开数据库连接)。

(2) 选择数据库中的“people”表。从这张数据表中,选择FIRST,LAST 和EMAIL 列。

(3) 在“Filter Data”(过滤器数据库)下,选择LAST,并选择“equals”(等于),加上参数Eckel。点

选“And”单选钮。

(4) 选择EMAIL,并选中“Is not Null”(不为空)。

(5) 在“Sort By”下,选择FIRST。

查询结果会向我们展示出是否能得到自己希望的东西。现在可以按下SQL 按钮。不需要我们任何方面的介入,正确的SQL 代码会立即弹现出来,以便我们粘贴和复制。对于这个查询,相应的SQL 代码如下:

SELECT people.FIRST,people.LAST, people.EMAIL

FROM people.csv people

WHERE (people.LAST=‘Eckel‘) AND

(people.EMAIL Is Not Null)

ORDER BY people.FIRST

若查询比较复杂,手工编码极易出错。但利用一个查询工具,就可以交互式地测试自己的查询,并自动获得正确的代码。事实上,亲手为这些事情编码是难以让人接受的。

5. 步骤5:在自己的查询中修改和粘贴

我们注意到上述代码与程序中使用的代码是有所区别的。那是由于查询工具对所有名字都进行了限定,即便涉及的仅有一个数据表(若真的涉及多个数据表,这种限定可避免来自不同表的同名数据列发生冲突)。由于这个查询只需要用到一个数据表,所以可考虑从大多数名字中删除“people”限定符,就象下面这样:

SELECT FIRST, LAST, EMAIL

FROM people.csv people

WHERE (LAST=‘Eckel‘) AND

(EMAIL Is Not Null)

580

ORDER BY FIRST

此外,我们不希望“硬编码”这个程序,从而只能查找一个特定的名字。相反,它应该能查找我们在命令行

动态提供的一个名字。所以还要进行必要的修改,并将SQL 语句转换成一个动态生成的字串。如下所示:

"SELECT FIRST, LAST, EMAIL" +

"FROM people.csv people" +

"WHERE " +

"(LAST=‘" + args[0] +"‘) " +

" AND (EMAIL Is Not Null)" +

"ORDER BY FIRST");

SQL 还有一种方式可将名字插入一个查询,名为“程序”(Procedures),它的速度非常快。但对于我们的大多数实验性数据库操作,以及一些初级应用,用Java 构建查询字串已经很不错了。从这个例子可以看出,利用目前找得到的工具——特别是查询构建工具——涉及SQL 及JDBC 的数据库编程是非常简单和直观的。

3     程序的G U I 版本

最好的方法是让查找程序一直保持运行,要查找什么东西时只需简单地切换到它,并键入要查找的名字即可。下面这个程序将查找程序作为一个“application/applet ”创建,且添加了名字自动填写功能,所以不必键入完整的姓,即可看到数据:

3.1     代码

import java.awt.*;

import java.awt.event.*;

import java.applet.*;

import java.sql.*;

public
class
VLookup extends Applet {

String dbUrl =
"jdbc:odbc:people";

String user =
"";

String password =
"";

Statement s;

TextField searchFor =
new TextField(20);

Label completion =
new Label(" ");

TextArea results =
new TextArea(40, 20);

public
void
init() {

searchFor.addTextListener(new SearchForL());

Panel p =
new Panel();

p.add(new Label("Last name to search for:"));

p.add(searchFor);

p.add(completion);

setLayout(new BorderLayout());

add(p, BorderLayout.NORTH);

add(results, BorderLayout.CENTER);

try {

// Load the driver (registers itself)

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

Connection
c = DriverManager.getConnection(dbUrl,
user, password);

s =
c.createStatement();

} catch (Exception
e) {

results.setText(e.getMessage());

}

}

class SearchForL
implements TextListener {

public
void
textValueChanged(TextEvent
te) {

ResultSet
r;

if (searchFor.getText().length() == 0) {

completion.setText("");

results.setText("");

return;

}

try {

// Name completion:

r =
s.executeQuery("SELECT LAST FROM people.csvpeople " +
"WHERE(LAST Like ‘" +
searchFor.getText()

+
"%‘) ORDER BY LAST");

if (r.next())

completion.setText(r.getString("last"));

r =
s.executeQuery("SELECT FIRST, LAST, EMAIL" +
"FROMpeople.csv people " +
"WHERE (LAST=‘"

+
completion.getText() + "‘) AND (EMAIL Is Not Null) " +
"ORDER BY FIRST");

} catch (Exception
e) {

results.setText(searchFor.getText() +
"\n");

results.append(e.getMessage());

return;

}

results.setText("");

try {

while (r.next()) {

results.append(

r.getString("Last")+
", "+ r.getString("fIRST")+
": "+ r.getString("EMAIL")+
"\n");

}

} catch (Exception
e) {

results.setText(e.getMessage());

}

}

}

public
staticvoid
main(String[]
args){

VLookup applet =
new VLookup();

Frame aFrame =
new Frame("Email lookup");

aFrame.addWindowListener(new WindowAdapter() {

public
void
windowClosing(WindowEvent
e) {

System.exit(0);

}

});

aFrame.add(applet, BorderLayout.CENTER);

aFrame.setSize(500, 200);

applet.init();

applet.start();

aFrame.setVisible(true);

}

} /// :~

数据库的许多逻辑都是相同的,但大家可看到这里添加了一个TextListener,用于监视在TextField(文本字段)的输入。所以只要键入一个新字符,它首先就会试着查找数据库中的“姓”,并显示出与当前输入相符的第一条记录(将其置入completion Label,并用它作为要查找的文本)。因此,只要我们键入了足够的字符,使程序能找到与之相符的唯一一条记录,就可以停手了。

4     J D B C A P I

阅览JDBC 的联机帮助文档时,我们往往会产生畏难情绪。特别是DatabaseMetaData 接口——与Java 中看到的大多数接口相反,它的体积显得非常庞大——存在着数量众多的方法,比如dataDefinitionCausesTransactionCommit(),getMaxColumnNameLength(),getMaxStatementLength(),

storesMixedCaseQuotedIdentifiers(),supportsANSI92IntermediateSQL(),supportsLimitedOuterJoins()

等等。它们有这儿有什么意义吗?

正如早先指出的那样,数据库起初一直处于一种混乱状态。这主要是由于各种数据库应用提出的要求造成的,所以数据库工具显得非常“强大”——换言之,“庞大”。只是近几年才涌现出了SQL 的通用语言(常用的还有其他许多数据库语言)。但即便象SQL 这样的“标准”,也存在无数的变种,所以JDBC 必须提供一个巨大的DatabaseMetaData 接口,使我们的代码能真正利用当前要连接的一种“标准”SQL 数据库的能力。简言之,我们可编写出简单的、能移植的SQL。但如果想优化代码的执行速度,那么为了适应不同数据库类型的特点,我们的编写代码的麻烦就大了。当然,这并不是Java
的缺陷。数据库产品之间的差异是我们和JDBC 都要面对的一个现实。但是,如果能编写通用的查询,而不必太关心性能,那么事情就要简单得多。即使必须对性能作一番调整,只要知道最终面向的平台,也不必针对每一种情况都编写不同的优化代码。

在Sun 发布的Java1.1 产品中,配套提供了一系列电子文档,其中有对JDBC 更全面的介绍。此外,在由Hamilton Cattel 和Fisher 编著、Addison-Wesley 于1997 年出版的《JDBC Database Access with Java》中,也提供了有关这一主题的许多有用资料。同时,书店里也经常出现一些有关JDBC 的新书。

时间: 2024-10-08 15:25:48

73.JAVA编程思想——JDBC的相关文章

java编程思想总结(三)

java编程思想总结(三) java编程思想总结是一个持续更新的系列,是本人对自己多年工作中使用到java的一个经验性总结,也是温故而知新吧,因为很多基础的东西过了这么多年,平时工作中用不到也会遗忘掉,所以看看书,上上网,查查资料,也算是记录下自己的笔记吧,过一段时间之后再来看看也是蛮不错的,也希望能帮助到正在学习的人们,本系列将要总结一下几点: 面向对象的编程思想 java的基本语法 一些有趣的框架解析 实战项目的整体思路 代码的优化以及性能调优的几种方案 整体项目的规划和视角 其它遗漏的东西

77.JAVA编程思想——模拟垃圾回收

77.JAVA编程思想--模拟垃圾回收 这个问题的本质是若将垃圾丢进单个垃圾筒,事实上是未经分类的.但在以后,某些特殊的信息必须恢复,以便对垃圾正确地归类.在最开始的解决方案中,RTTI 扮演了关键的角色.这并不是一种普通的设计,因为它增加了一个新的限制.正是这个限制使问题变得非常有趣--它更象我们在工作中碰到的那些非常麻烦的问题.这个额外的限制是:垃圾抵达垃圾回收站时,它们全都是混合在一起的.程序必须为那些垃圾的分类定出一个模型.这正是RTTI 发挥作用的地方:我们有大量不知名的垃圾,程序将正

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接

《Java编程思想》第十三章 字符串

<Java编程思想>读书笔记 1.String作为方法的参数时,会复制一份引用,而该引用所指的对象其实一直待在单一的物理位置,从未动过. 2.显式地创建StringBuilder允许预先为他指定大小.如果知道字符串多长,可以预先指定StringBuilder的大小避免多次重新分配的冲突. 1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月1日 下午4:03:59 4 */ 5 public class UsingStringBuilder {

Java编程思想 4th 第2章 一切都是对象

Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情在类对象中完成. 在Java中,使用引用来操纵对象,在Java编程思想的第四版中,使用的术语是"引用(reference)",之前有读过Java编程思想第三版,在第三版中,使用的术语是"句柄(handle)",事实上,我觉得第三版的术语"句柄"更加形象传神,就像你用一个

《Java编程思想(第4版)》pdf

下载地址:网盘下载 内容简介 编辑 本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形.从Java的基础语法到最高级特性(深入的面向对象概念.多线程.自动项目构建.单元测试和调试等),本书都能逐步指导你轻松掌握.[1] 从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作.本书的作者拥有多年教学经验,对C.C++以及Java语言都有独到.深入的见解,以通俗易懂及小而直接的示例解释了一个个晦涩抽象的概

Java编程思想总结笔记Chapter 2

本章介绍Java程序的基本组成部分,体会到Java中几乎一切都是对象. 第二章   一切都是对象 目录: 2.1 用引用操纵对象 2.2 必须由你创建所有对象 2.3 永远不需要销毁对象 2.4 创建新的数据类型:类 2.5 方法.参数和返回值 2.6 构建一个Java程序 2.7 你的第一个Java程序 2.8 注释和嵌入式文档 2.9 编码风格 2.1 用引用操纵对象 一切都看作对象,操纵的标识符实际上是对象的一个"引用",遥控器(引用)操纵电视机(对象),想调控电视,只需通过遥控

《java编程思想》有必要买吗

<java编程思想>有必要买吗 1.看到过好多个这样的提问,其实我一般真的不那么容易分享自己的这点心得的,这是第一次回答这样的"推荐书籍"方面的问题. 我买编程方面的书籍,有一个非常清晰.坚决的原则--电子工业出版社的! 对于JAVA,建议你看如下的书: 首先,<21天学通JAVA>: 然后,<30天学通JAVA项目案例开发>(这本书的内容都是实例的,非常棒的实例!适合初学者的同时,又有实际应用性!) 以上的书籍,是基于你只想学J2SE的. 我还建议

JAVA编程思想(第四版)学习笔记----4.8 switch(知识点已更新)

switch语句和if-else语句不同,switch语句可以有多个可能的执行路径.在第四版java编程思想介绍switch语句的语法格式时写到: switch (integral-selector) { case integral-value1: statement; break; case integral-value12: statement; break; default: statement; } 其中integral-selector(整数选择因子)是一个能产生整数值的表达式.并且说