当前位置: 首页 > 图灵资讯 > 技术篇> 使用 JDBC 创建数据库对象 1

使用 JDBC 创建数据库对象 1

来源:图灵教育
时间:2024-02-28 17:14:41
本文分析了Java DataBase Connectivity (JDBC),一个在 Java 以面向对象的方式连接数据库的技术。它是对 ODBC API 一种面向对象的包装和重新设计,易于学习和使用,可以使您编写不依赖供应商的代码来查询和操作数据库。JDBC 提供了一些相当低的方法来访问数据库,同时也提供了相当高的对象来处理数据库。

什么是数据库? 数据库是一系列存储在某个文件结构中的信息表,允许您访问这些表,选择表中的列,排序表,并根据各种标准选择行。数据库通常有多个索引与这些表中的许多列相关,所以我们可以尽快访问这些表。

在计算过程中,数据库比其他类型的结构更常用。您会发现数据库在员工记录和薪酬系统中处于核心地位,数据库可以在旅行计划系统中找到,在产品生产和销售的整个过程中找到。

以员工记录为例,您可以想象一个包含员工姓名、地址、工资、扣税和津贴的表格。让我们考虑一下如何组织这些内容。您可以想象一个包含员工姓名、地址和电话号码的表格。您希望保存的其他信息可能包括工资、工资范围、上次加薪时间、下次加薪时间、员工绩效评估等。

这些内容应该保存在一个表格中吗?几乎当然不是这样。不同类型员工的工资范围可能没有差异;这样,您只能将员工类型存储在员工记录表中,并将工资范围存储在另一个表中,并通过类型号与该表相关联。考虑以下情况:

Key Lastname SalaryType SalaryType Min Max 1 Adams 2 1 30000 45000 2 Johnson 1 2 45000 60000 3 Smyth 3 3 60000 75000 4 Tully 1 5 Wolff 2

SalaryType 列中的数据引用第二个表。我们可以想象许多这样的表格,如存储住宅城市和每个城市的税收价值、健康计划扣除金额等。每个表都有一个主键列(如上面两个表中最左边的列)和几个数据列。在数据库中建立表格既是一门艺术,也是一门科学。它们的范式指出了这些表的结构。我们通常说表属于第一、第二或第三范式,简称第一、第二或第三范式 1NF、2NF 或 3NF。

第一范式:表中的每个表元应该只有一个值(永远不可能是一个数组)。(1NF)

第二种范式:满足 1NF,每个副键列完全依赖于主键列。这意味着主键和银行中剩余的表元之间是 1 对 1 关系。(2NF)

第三种范式:满意度 2NF,所有副键列都是独立的。任何数据列中包含的值都不能从其他列的数据中计算出来。(3NF)

现在,几乎所有的数据库都是基于“第三范式” (3NF)创建。这意味着通常有相当多的表,每个表中的信息列相对较少。 从数据库中获取数据 假设我们想生成一个包含员工及其工资范围的表,这个表将在我们设计的实践中使用。该表格不直接存在于数据库中,但可以通过向数据库发送查询来构建。我们希望得到以下表格:

Name Min Max Adams $45,000.00 $60,000.00 Johnson $30,000.00 $45,000.00 Smyth $60,000.00 $75,000.00 Tully $30,000.00 $45,000.00 Wolff $45,000.00 $60,000.00

或者,按照工资增加的顺序排序

Name Min Max Tully $30,000.00 $45,000.00 Johnson $30,000.00 $45,000.00 Wolff $45,000.00 $60,000.00 Adams $45,000.00 $60,000.00 Smyth $60,000.00 $75,000.00

我们发现这些表格的查询形式如下所示

SELECT DISTINCTROW Employees.Name, SalaryRanges.Min, SalaryRanges.Max FROM Employees INNER JOIN SalaryRanges ON Employees.SalaryKey = SalaryRanges.SalaryKey ORDER BY SalaryRanges.Min; 这种语言称为结构化查询语言,即 SQL(一般读作 "sequel"),它是目前几乎所有数据库都可以使用的一种语言。若于这几年已经颁布了 SQL 而且大部分都是标准 PC 大部分数据库都支持数据库 ANSI 标准。若于近年来已颁布 SQL 而且大部分都是标准 PC 大部分数据库都支持数据库 ANSI 标准。SQL-92 该标准被认为是一种基本标准,已多次更新。然而,没有一个数据库能完美地支持以后的数据库 SQL 大多数数据库提供各种版本 SQL 为了支持数据库的独特性能而进行扩展。 由于数据库的类型 PC 它已经成为主要的办公工具,因此已经开发出来了 PC 大量流行的数据库可以自行管理。它们包括初级数据库,如 Microsoft Works,它还包括更复杂的数据库,如 Approach、 dBase、Borland Paradox、Microsoft Access 和 FoxBase。

另一类 PC 包括那些可以由多个数据库的数据库? PC 通过服务器访问客户机的数据库。其中包括 IBM DB/2、Microsoft SQL Server、 Oracle、Sybase、SQLBase 和 XDB。所有这些数据库产品都支持各种相对相似的产品 SQL 因此,所有数据库最初似乎都可以交换。当然,它们之所以不能交换,是因为每个数据库都有不同的性能特征,每个数据库都有不同的用户界面和编程界面。你可能会想,既然他们都支持, SQL,它们的编程也应该相似,但这是绝对错误的,因为每个数据库都以自己的方式接收它们 SQL 查询并以自己的方式返回结果。这自然导致了新一代的标准:ODBC 如果ODBC能够以某种方式编写不依赖特定制造商的数据库代码,并且能够从这些数据库中获得相同的结果而不改变其调用程序,那将是一件好事。如果我们只能为所有这些数据库编写一些包装,使它们具有类似的编程界面,那么这种独立于供应商的数据库编程特性将很容易实现。

Microsoft 于 1992 该公司首先尝试了这一技能,并发布了一个标准,称为对象数据库连接。这被认为是在 Windows 所有数据库在环境中连接的答案。与所有软件的第一个版本相同,它也经历了一些发展问题 1994 这一年又推出了另一个版本,运行速度更快,更稳定。它也是第一个 32 位的版本。另外,ODBC 开始向 Windows 其他平台的发展,到目前为止,它已经发展起来了 PC 而且工作站领域已经很普遍了。几乎每个主要数据库制造商都提供它 ODBC 驱动程序。

然而,ODBC 这不是我们最初想象的灵丹妙药。很多数据库厂商都会 ODBC 作为标准接口以外的“替代接口”,并对其进行处理 ODBC 编程微不足道。与其它 Windows 就像编程一样,它包括句柄、指针和选项,使其难以掌握。最后一点,ODBC 不是中立的标准。它由 Microsoft 公司开发并不断改进,微软还推出了我们所有人使用的竞争性软件平台,这使得ODBC的未来难以预测。 什么是 JDBC?JDBC 是一组首字母缩写,曾代表“Java DataBase Connectivity但现在它已经成为一个商标符号。它是对 ODBC API 一种面向对象的包装和重新设计,易于学习和使用,真的可以让你编写不依赖制造商的代码来查询和操作数据库。尽管它与一切相关 Java API 同样,它们都是面向对象的,但它们不是很高级别的对象集。在本章的剩余部分,我们将提出更高级别的方法。

除 Microsoft 此外,大多数制造商都使用它 JDBC,并为其数据库提供 JDBC 驱动程序;这让你很容易真正编写几乎完全不依赖数据库的代码。另外,JavaSoft 和 Intersolv 已开发出一种名称 JDBC-ODBC Bridge 产品,可以让你没有直接连接 JDBC 驱动程序的数据库。支持 JDBC 所有数据库至少必须得到支持 SQL-92 标准。这在很大程度上实现了跨数据库和平台的可移植性。 安装和使用 JDBCJDBC 所有类别都被归类 java.sql 包装,安装 Java JDK 1.1 或者自动安装更高的版本。但是,如果你想用的话 JDBC-ODBC 另外两个程序包必须安装在桥上。首先,如果你使用它 Windows 95,一定是你的 ODBC 驱动程序升级为 32 您可以从位驱动程序 Microsoft 网站下载。这个驱动程序在 Microsoft 很难在网站上找到;请搜索 DataAcc.exe 并下载和安装。

JDBC-ODBC 驱动程序可以从 Sun 的 Java 网站 (http://java.sun.com) 很容易找到并下载。在您扩展并安装此驱动程序后,必须执行以下步骤: 将 \jdbc-odbc\classes; 添加到你身上的路径 PATH 在环境变量中。 将 \jdbc-odbc\classes; 添加到你身上的路径 CLASSPATH 在环境变量中。 在 Windows 95 把它们放在环境中 autoexec.bat 重新引导文件,使所有设置生效。 在 Windows NT 在环境中,将其添加到“控制面板”中“系统”对象的“环境”选项卡中,退出并重新登录,使其生效。 JDBC Java驱动程序类型 实际上,程序连接数据库有四种方法: JDBC-ODBC 桥和 ODBC 驱动程序 -- 这样,这是一个本地解决方案,因为 ODBC 用户的每台机器都必须出现驱动程序和桥码。从根本上说,这是一个临时解决方案。

本机代码和 Java 驱动程序 -- 它使用了另一个本地解决方案(平台上 Java 可调本机代码)替换 ODBC 和 JDBC-ODBC 桥。

JDBC 网络的纯 Java 驱动程序 -- 由 Java 驱动程序翻译 JDBC 形成传输到服务器的独立协议。然后,服务器可以连接到任何数量的数据库。这种方法使您可以从客户机 Applet 中调服务器,并将结果返回您 Applet。在这种情况下,中间软件提供商可以提供服务器。

本机协议 Java 驱动程序 -- Java 驱动程序直接转换为数据库协议并调用。这种方法也可以通过网络使用,也可以在网络中使用 Web 浏览器的 Applet 显示结果。在这种情况下,每个数据库制造商都将提供驱动程序。 如果你想编写代码来处理它 PC 如客户机数据库 dBase、Foxbase 或 Access,然后你可以使用第一种方法,并且拥有用户机器上的所有代码。更大的客户机-服务器数据库产品(如 IBM 的 已经提供了DB2 3 等级驱动程序。 当数据库和查询其应用程序在同一台机器上且没有服务器代码干预时,我们将生成的两层模型和三层模型称为两层模型。一层是应用程序,另一层是数据库。在 JDBC-ODBC 这通常发生在桥梁系统中。

当应用程序或 applet 当服务器再次调用数据库时,我们称之为三层模型。这种情况通常是在你调用被称为“服务器”的程序时。 编写 JDBC 现在,我们将开始查看如何编写代码访问数据库 Java 访问数据库的程序。我们想要使用的数据库被称为 groceries.mdb 的 Microsoft Access 数据库。该数据库中的数据由三家当地杂货店中一些常见商品的价格组成。食品表如下:

FoodKey FoodName 1 Apples 2 Oranges 3 Hamburger 4 Butter 5 Milk 6 Cola 7 Green beans

杂货店表如下:

StoreKey StoreName 1 Stop and Shop 2 Village Market 3 Waldbaum's

杂货店定价表仅由三种表格中的键值和价格组成:

FSKey StoreKey FoodKey Price 1 1 1 $0.27 2 2 1 $0.29 3 3 1 $0.33 4 1 2 $0.36 5 2 2 $0.29 6 3 2 $0.47 7 1 3 $1.98 8 2 3 $2.45 9 3 3 $2.29 10 1 4 $2.39 11 2 4 $2.99 12 3 4 $3.29 13 1 5 $1.98 14 2 5 $1.79 15 3 5 $1.89 16 1 6 $2.65 17 2 6 $3.79 18 3 6 $2.99 19 1 7 $2.29 20 2 7 $2.19 21 3 7 $1.99

用 ODBC 注册您的数据库 Windows 95 或 NT 环境下访问 ODBC 必须在数据库使用之前使用数据库 ODBC控制面板中的控制面板 注册驱动程序。在 Windows 95 在“控制面板”程序中,环境是 ODBC 图标。在 Windows NT 在环境中,您将在“开始”菜单中找到此程序。(如果找不到,需要安装上述内容 ODBC 驱动程序,即 WX1350.exe)。

双击 ODBC 图标,然后单击“添加” 1 所示。然后选择数据库驱动程序(这里使用) Microsoft Access),然后点击“确定”。分别在“数据源名”和“描述”中输入数据源名称 (Groceries) 和数据库说明 (Grocery prices)(这两项都不需要与文件名相关),然后单击“选择”,找到数据库并选择数据库。在找到数据库后,屏幕将如图所示 2 所示。单击“确定”,然后单击“关闭”关闭面板。

图 1:ODBC 屏幕设置在控制面板上。

图 2:在 ODBC 在控制面板中选择数据库和说明。

所有与数据库相关的对象和方法都在连接数据库 java.sql 所以在包里使用 JDBC 必须添加到程序中 "import java.sql.* "。 JDBC 要连接 ODBC 你必须先加载数据库,先加载数据库 JDBC-ODBC 桥驱动程序

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");这个句子加载了驱动程序,并创建了一个这样的例子。然后,为了连接特定的数据库,您必须创建它 Connect 一个类的例子,并使用它 URL 语法连接数据库。

String url = "jdbc:odbc:Grocery prices"; Connection con = DriverManager.getConnection(url);请注意,您使用的数据库名称是您使用的数据库名称 ODBC 在面板中设置输入的“数据源”名称。

URL 由于数据库类型的不同,语法可能会发生很大的变化。

jdbc:subprotocol:subname的第一组字符代表连接协议,而且总是 jdbc。在这里,子协议也可能被指定为子协议 odbc。它规定了一种数据库连接机制。如果您想连接其他机器上的数据库服务器,您还可以指定机器和子目录:

jdbc:bark//doggie在/elliott结束时,您可以指定用户名和密码作为连接字符串的一部分:

jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof 一旦访问数据库连接到数据库,您可以要求表名、名称和内容,并且您可以运行 SQL 查询数据库或添加或修改其内容。从数据库中获取信息的对象有:

DatabaseMetaData 关于整个数据库的信息:表名、表索引、数据库产品的名称和版本、数据库支持的操作。 ResultSet 关于某个表的信息或查询结果。您必须逐行访问数据行,但您可以按任何顺序访问列。 ResultSetMetaData 有关 ResultSet 中列的名称和类型信息。

虽然每个对象都有很多方法可以让你获得数据库元素的非常详细的信息,但有几种主要的方法可以让你获得最重要的数据信息。但是,如果您想看到比这里更多的信息,建议您学习文档以获得其他方法的解释。 ResultSetResultSet 对象是 JDBC 最重要的单个对象。本质上,它是对一般宽度和未知长度表的抽象。几乎所有的方法和查询都使用数据作为数据 ResultSet 返回。ResultSet 您可以根据名称访问任何数量的命名列。它还包含一个或多个行,您可以自上而下一个接一个地访问。在您使用 ResultSet 在此之前,必须查询它包含了多少列。存储此信息 ResultSetMetaData 对象中。

 

////从元数据中获得列数 ResultSetMetaData rsmd; rsmd = results.getMetaData(); numCols = rsmd.getColumnCount();

当你得到一个 ResultSet 当它指向第一行之前的位置时。你可以用它 next() 当没有更多的行时,该方法将返回到其他每一行 false。因为从数据库中获取数据可能会导致错误,所以你必须始终将结果集处理句子包括在一起 try 块中。

try { rsmd = results.getMetaData(); numCols = rsmd.getColumnCount(); boolean more = results.next(); while (more) { for (i = 1; i <= numCols; i++) System.out.print(results.getString(i)+" "); System.out.println(); more = results.next(); } results.close(); } catch(Exception e) {System.out.println(e.getMessage());}您可以以多种形式获得 ResultSet 中的数据,这取决于每列中存储的数据类型。此外,您还可以根据列号或列名获得列的内容。此外,您还可以根据列号或列名获得列号的内容。请注意,列号从 1 开始,而不是从 0 开始。ResultSet 一些最常用的对象方法如下所示。

getInt(int); 将序号为 int 列的内容作为整数返回。

getInt(String); 将名称为 String 列的内容作为整数返回。

getFloat(int); 将序号为 int 列的内容作为一个 float 型数返回。

getFloat(String); 将名称为 String 作为列的内容 float 型数返回。

getDate(int); 将序号为 int 列的内容作为日期返回。

getDate(String); 将名称为 String 列的内容作为日期返回。

next(); 将行指针移到下一行。如果没有剩余行,返回 false。

close(); 关闭结果集。

getMetaData(); 返回 ResultSetMetaData 对象。 Resultsetmetadata getMetaData() 方法从 ResultSet 中获取 ResultSetMetaData 对象。您可以使用此对象获得列的数量和类型以及每列的名称。

getColumnCount(); 返回 ResultSet 中的列数。

getColumnName(int); 返回序列号为 int 的列名。

getColumnLabel(int); 回到这一列暗示的标签。

isCurrency(int); 如果这个列包含一个有货币单位的数字,则返回 true。

isReadOnly(int); 如果列为只读,则返回 true。

isAutoIncrement(int); 如果这个列自动增加,则返回 true。这种列通常是键,而且总是只读。

getColumnType(int); 返回此列的 SQL 数据类型。包括这些数据类型 BIGINT BINARY BIT CHAR DATE DECIMAL DOUBLE FLOAT INTEGER LONGVARBINARY LONGVARCHAR NULL NUMERIC OTHER REAL SMALLINT TIME TIMESTAMP TINYINT VARBINARY VARCHAR DatabaseMetaDataDatabaseMetaData 对象可以为您提供整个数据库的信息。您主要使用它来获取数据库中表的名称和表中列的名称。您主要使用它来获取数据库中表的名称和表中列的名称。由于不同的数据库支持不同的数据库 SQL 因此,有很多方法可以查询数据库支持什么 SQL 方法。

getCatalogs() 返回数据库中的信息目录列表。使用 JDBC-ODBC Bridge 您可以使用驱动程序 ODBC 注册数据库列表。这很少用于 JDBC-ODBC 数据库。 getTables(catalog, schema, tableNames, columnNames) 返回表名与 tableNames 并且列名与之一致 columnNames 所有符合表格的说明。 getColumns(catalog, schema, tableNames, columnNames) 返回表名与 tableNames 并且列名与之一致 columnNames 一致的所有列表说明。

getURL(); 得到你连接的 URL 名称。

getDriverName(); 获取您连接的数据库驱动程序的名称。 您可以使用相关表格获取信息 DataBaseMetaData 的 getTables() 获取数据库中表信息的方法如下。 4 个 String 参数:

results = dma.getTables(catalog, schema, tablemask, types[]);参数的含义如下:

catalog 找到表名的目录名。对于 JDBC-ODBC 对于数据库和许多其他数据库,可以设置为 null。这些数据库的目录项实际上是其在文件系统中的绝对路径名称。

schema 包括数据库的“解决方案”。许多数据库不支持解决方案,但对于其他数据库,它代表了数据库所有者的用户名。它通常被设置为 null。

tablemask 用来描述你要检索的表的名称的掩码。如果您想检索所有表名,请将其设置为通配符 %。请注意,SQL 中间的通配符是 % 符号,而不是一般 PC 用户的 * 符号。

types[] 这是描述你想要检索的表的类型 String 数组。数据库通常包含许多用于内部处理的表,对用户来说毫无价值。如果是空值,你会得到所有这些表。如果您将其设置为包含字符串”TABLES单元素数组,您只会得到对用户有用的表格。

从数据库中获取表名的简单方法代码相当于获取 DatabaseMetaData 从对象中检索表名:

con = DriverManager.getConnection(url); ////元数据获取数据库 dma =con.getMetaData(); ///转储数据库中表的名称 String[] types = new String[1]; types[0] = "TABLES"; //设置查询类型 //请注意通配符是 % 符号(而非“*”) results = dma.getTables(null, null, "%", types);

然后,我们可以打印出表名,正如我们上面所做的:

boolean more = results.next(); while (more) { for (i = 1; i <= numCols; i++) System.out.print(results.getString(i)+" "); System.out.println(); more = results.next(); }如前文所述,包括所有代码 try 块中。 执行 SQL 我们已经理解了查询 JDBC 现在可以执行基本对象 SQL 查询了。 执行 SQL 我们已经理解了查询 JDBC 现在可以执行基本对象 SQL 查询。查询就是这样 Statement 执行对象的方法,你很容易从 Connection 对象获得Statement对象:

String query = "SELECT FoodName FROM Food;"; ResultSet results; try { Statement stmt = con.createStatement(); results = stmt.executeQuery(query); } catch (Exception e) {System.out.println("query exception");}请注意,这个简单的查询返回 Food 表中的整个 FoodName 列。您使用如此简单的查询来获取整个列的内容。您使用如此简单的查询来获取整个列的内容。请注意,查询本身就是一个 ResultSet,你可以用我们刚才讨论过的方法来处理它。 打印 Resultset,因为我们总是从 ResultSets 在打印数据时,我们可以设计一种简单的方法来设计整个数据 ResultSet 包括表名元数据在内的转存。子程序如下所示:

private void dumpResults(String head) { ///这是打印列标头和每列的内容 //一般方法 System.out.println(head); try { ////从元数据中获得列数 rsmd = results.getMetaData(); numCols = rsmd.getColumnCount(); ///打印列名 for (i = 1; i<= numCols; i++) System.out.print(rsmd.getColumnName(i)+" "); System.out.println(); ///打印列内容 boolean more = results.next(); while (more) { for (i = 1; i <= numCols; i++) System.out.print(results.getString(i)+" "; System.out.println(); more = results.next(); } } catch(Exception e) {System.out.println(e.getMessage());} } 一个简单的 JDBC 我们已经学会了程序 JDBC 所有基本功能,现在我们可以编写一个简单的程序,打开数据库,打印其表名和表列内容,然后查询数据库。该程序如下:

import java.net.URL; import java.sql.*; import java.util.*; class JdbcOdbc_test { ResultSet results; ResultSetMetaData rsmd; DatabaseMetaData dma; Connection con; int numCols, i; //-- public JdbcOdbc_test() { String url = "jdbc:odbc:Grocery prices"; String query = "SELECT DISTINCTROW FoodName FROM Food " + "WHERE (FoodName like 'C%');"; try { //加载 JDBC-ODBC 桥驱动程序 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //连接数据库 con = DriverManager.getConnection(url); ////元数据获取数据库 dma =con.getMetaData(); System.out.println("Connected to:"+dma.getURL()); System.out.println("Driver "+dma.getDriverName()); //转储数据库中表的名称 String[] types = new String[1]; types[0] = "TABLES"; //请注意通配符是 % 符号(而非“*”) results = dma.getTables(null, null, "%", types); dumpResults("--Tables--"); results.close(); } catch (Exception e) {System.out.println(e);} //获取表列名称 System.out.println("--Column Names--"); try { results = dma.getColumns(null, null, "FoodPrice", null); ResultSetMetaData rsmd = results.getMetaData(); int numCols = rsmd.getColumnCount(); while (results.next() ) String cname = results.getString("COLUMN_NAME"); System.out.print(cname + " "); System.out.println(); results.close(); } catch (Exception e) {System.out.println(e);} ///列出列的内容 -- 这是一个查询 try { Statement stmt = con.createStatement(); results = stmt.executeQuery("SELECT FOODNAME FROM FOOD;"); } catch (Exception e) {System.out.println("query exception");} dumpResults("--Contents of FoodName column--"); //尝试实际 SQL 语句 try { Statement stmt = con.createStatement(); results = stmt.executeQuery(query); } catch (Exception e) {System.out.println("query exception");} dumpResults("--Results of Query--"); }该程序打印的结果如下:

C:\Projects\objectJavachapter19>java JdbcOdbc_test Connected to:jdbc:odbc:Grocery prices Driver JDBC-ODBC Bridge (ODBCJT32.DLL) --Tables-- TABLE_QUALIFIER TABLE_OWNER TABLE_NAME TABLE_TYPE REMARKS groceries null Food TABLE null groceries null FoodPrice TABLE null groceries null Stores TABLE null --Column Names-- FSKey StoreKey FoodKey Price --Contents of FoodName column-- FOODNAME Apples Oranges Hamburger Butter Milk Cola Green beans --Results of Query-- FoodName Colaxx