《JavaTM程序设计语 言基础》第 1 部分
第 7 课:数据库访问及权限

[<<返回] [目录]] [下一个>>]

本课将利用 JDBC TM 对第 6 课中的应用 程序、applet 程序和 servlet 程序的示例进行适当修改,使之能够实现与数据 库之间的数据读写操作。JDBC 是 Java 2 平台上使用的 JavaTM 数据库连接应用编程接口(API)。

本课中所使用的代码与您在第 6 课中所见到的代码非常类似,但包含了更多的 操作步骤(不仅仅是把文件访问代码转换成数据库访问代码),包括设置环境、 创建数据库表、连接数据库。创建数据库表是一项您的程序代码中没有包括的数 据库管理任务。而创建数据库连接和由之而来的数据库访问则是您程序代码中的 组成部分。

正如第 6 课所述,applet 程序需要得到适当的许可后方可连接到数据库。其 所需要的权限随数据库连接时所使用的驱动程序的不同而不同。


数据库设置

若想运行本课中的示例程序,就需要获得对数据库的访问权限。您可以在您的 计算机上安装一个数据库,或者您可能有权使用正在运行的数据库。无论是何种 情况,您都需要相关的数据库驱动程序和环境参数设置,这样您的程序才能加载 驱动程序并能在数据库中查找数据。程序还需要由用户名和密码表示的数据库登 录信息。

数据库驱动程序是使程序创建与数据库相连接的软件。如果没有适合于需要连 接的数据库的正确驱动程序,您的程序就无法创建连接。

驱动程序或者与数据库一起提供,或者可到网络下载。如果要安装自己的数据 库,则请在驱动程序的文档中查找您的平台所需要的相关安装信息和其它环境设 置。若要使用系统所采用的数据库,则请向数据库管理员索要相关信息。

为了给您的这些操作提供两种途径,应用程序示例使用了 jdbc 驱动程序、applet 程序示例使用了 jdbcjdbc.odbc 驱动程序,而 servlet 程序示例则使用了 jdbc.odbc 驱动程序。 所有程序示例都连接到一个 OracleOCI7.3.4 数据库。

与其它数据库的连接步骤和程序与此类似。若需要数据库连接方面的帮助,请 查阅相关文档或向系统管理员咨询。

创建数据库表

获得数据库访问权限后,就可以为本课中的示例创建一个数据库表。您需要一 个有文本域的表来保存字符数据。

TABLE DBA (
        TEXT            varchar2(100),
        primary key (TEXT)
)

应用程序对数据库的访问

本例将修改第 6 课中的 FileIO 程序,使之实现向数据库读写数据的功能。启动应用程序 Dba 时,将出现下图上方的窗口;而点击 Click Me 按钮时, 则将出现下图下方的窗口。

点击 Click Me 按钮后,文本域中所输入的任何内容都将保存 到数据库中。之后,就可以在数据库中检索这些数据,或把数据显示在下方窗口 中。如果需要不止一次向表中写入数据而每次写入的数据都要读入并显示在下方 窗口中,那么就需要增加该窗口的尺寸,以便能看到表中的所有记录。

应用程序启动时

向数据库中写入数据(橙子和苹果)后

访问数据库的应用程序需要一段代码来创建与数据库的连接并执行数据库读写 操作。

创建数据库连接

JDBC DriverManager 类可处理多个数据库驱动程序并对全部数 据库通信进行初始化。若要加载驱动程序并连接到数据库,应用程序就需要使用 表示 _driver_urlConnection 对象和 Strings

_url 串是以统一资源地址(URL)的形式出现的。其组成包括 URL、Oracle 子协议和 jdbc:oracle:thin 形式的数据源、数据库 登录用的 username(用户名)和 password(密码) 以及相关的机器、端口和协议信息。

private Connection c;

final static private String _driver = 
  "oracle.jdbc.driver.OracleDriver";

final static private String _url = 
 "jdbc:oracle:thin:username/password@(description=(
 address_list=(address=(protocol=tcp)
 (host=developer)(port=1521)))
 (source_route=yes)(connect_data=(sid=jdcsid)))";

actionPerformed 方法调用 Class.forName(_driver) 方法来加载驱动程序,而调用 DriverManager.getConnection 方 法来创建连接。第 6 课中的 异常处理 部分 描述了 trycatch 程序块。其中的唯一不同是 本程序块由于可能存在两种不同的错误而使用了两个 catch 语句。

调用 Class.forName(_driver);; 将抛出 java.lang.ClassNotFoundException, 而调用 c = DriverManager.getConnection(_url);; 则抛出 java.sql.SQLException。当其中的任何一种出错情况发生时,应 用程序都会把所发生的故障告诉用户并退出,这是因为没有数据库驱动程序或不 能连接就无法实现任何有意义的操作。

public void actionPerformed(ActionEvent event){
  try{
//Load the driver
     Class.forName(_driver);
//Establish database connection
     c = DriverManager.getConnection(_url);
   }catch (java.lang.ClassNotFoundException e){
     System.out.println("Cannot find driver class");
     System.exit(1);
   }catch (java.sql.SQLException e){
     System.out.println("Cannot get connection");       
     System.exit(1);
   }

最终变量和私有变量

用于创建上述数据库连接的成员变量被声明为 private(私有变 量),而其中有两个变量被声明为 final(最终变量)。

最终变量(final): final变量包含一个经 初始化后不再改变的常数值。示例中,用户名和密码都是 final 变量,因为您并不希望出现实例或其他任何类改变这些信息。

私有变量 (private): private变量只能为 定义了该变量的类所使用(访问)。任何未定义该 private 变量 的类都不能访问或改变它。示例中,数据库驱动程序、用户名和密码变量都定义 为 private 变量,以防止外部类访问它并危及数据库连接,或破 坏作为保密信息的用户名和密码。这方面的详细说明可见于 Java 教程 中的 对象和类 一课中。

写数据和读数据

在写数据(write)操作中,Statement(语句)对象是根据 Connection(连接)创建的。Statement 对象有执 行 SQL 查询和更新的方法。其次,构建包含写操作 SQL 更新的 String (串)对象,并传递给 Statement 对象的 executeUpdate 方法。

Object source = event.getSource();
if(source == button){
  if(_clickMeMode) {
    JTextArea displayText = new JTextArea();
    try{
  //Code to write to database
     String theText = textField.getText();
     Statement stmt = c.createStatement();
     String updateString = "INSERT INTO dba VALUES 
			   ('" + theText + "')";
     int count = stmt.executeUpdate(updateString);

SQL 命令为 String 对象,所以遵循双引号("")为串分隔符、 变量数据插入采用加号(+)标识的 String 构造规则。变量 theText 是一个文本变量。为符合 SQL 的语法要求,事先插入了 一对单引号。

在读操作中,ResultSet 对象是从 Statement 对象的 executeQuery 方法中创建的。ResultSet 包 含查询程序返回的数据。若要检索返回的数据,程序就会在 ResultSet 中以叠代算法循环操作、检索数据并把数据插入到文本区 displayText 中。

//Code to read from database
      ResultSet results = stmt.executeQuery(
	"SELECT TEXT FROM dba ");
      while(results.next()){
        String s = results.getString("TEXT");
        displayText.append(s + "\n");
      }
      stmt.close();
    } catch(java.sql.SQLException e){
      System.out.println("Cannot create SQL statement");
    }
//Display text read from database
    text.setText("Text retrieved from database:");
    button.setText("Click Again");
    _clickMeMode = false;
  } else {
    text.setText("Text to save to database:");
    textField.setText("");
    button.setText("Click Me");
    _clickMeMode = true;
  }
}

Applet 程序对数据库的访问

applet 程序的示例类似于前文所述的应用程序,不同之处是第 3 课中 结构和组成部分 一节所述的应用程序和 applet 程序之间的标准区别。

但是,如果您运行没有策略文件的 applet 程序,栈跟踪会指示出权限错误。 第 6 课中的 授予 Applet 程序权限 一节已经为 您介绍了策略文件和如何向 applet 程序授予其所需要的权限。第 6 课中的 applet 示例程序提供了该策略文件并告诉了您如何运行带有该策略文件的 applet 程序。本课将为您介绍如何读取栈跟踪,以确定策略文件中所需要的权 限。

为使程序具有一定的趣味性,本课讨论了两个版本的访问数据库的 applet 程 序:其一是用 JDBC 驱动程序,另一种是采用带有开放数据库连接(ODBC)驱动 程序的 JDBC-ODBC 桥接。

这两个 applet 程序都对统一数据库表执行同样的操作,只是使用了不同的驱 动程序。每个 applet 程序都有自己附带不同权限列表的策略文件,并对数据库 驱动程序的定位有不同的要求。

JDBC 驱动程序

JDBC 驱动程序为利用 Java 语言(Java 程序)专门编写的程序所使用。它 把 JDBC 调用直接转换成为 DBMS 所使用的协议。这种驱动程序可向 DBMS 厂家 索取,通常与 DBMS 软件打包一起提供。

启动 Applet 程序:为使运行成功, DbaAppl.java applet 程序需要一个可用数据库驱动程序和一个策略文件。 本节将讲述相关的设置步骤。以下是运行 DbaAppl applet 程序 的 DbaAppl.html 文件:

<HTML>
<BODY>

<APPLET CODE=DbaAppl.class
  WIDTH=200
  HEIGHT=100>
</APPLET>

</BODY>
</HTML>

用 appletviewer 启动 applet 程序的代码如下:

  appletviewer DbaAppl.html

定位数据库驱动程序:假设由于某种原因驱动程序对 DriverManager 不可用,那么在您点击 Click Me 按钮时,就会出现以下错误。

  cannot find driver

这一出错信息的意思是,DriverManager 已在 applet HTML 和类文件所在的目 录中查找过 JDBC 驱动程序,但是没有找到。若要纠正这一错误,就应把该驱动 程序拷贝到 applet 文件所在的目录下。如果该驱动程序是以压缩文件形式存在 的,则应对该压缩文件执行解压缩操作,以便 applet 程序能够访问到驱动程 序。

驱动程序安装到位后,即可再次运行 applet 程序。/P>

  appletviewer DbaAppl.html

读取栈跟踪:如果驱动程序可在本地应用于 applet 程序, 那么在 DbaAppl.java applet 程序运行但没有策略文件时,就会在终端用户点击 Click Me 按钮时生成以下栈跟踪:

java.security.AccessControlException: access denied 
(java.net.SocketPermission developer resolve)

上述栈跟踪的第一行代码通知您访问被拒绝。这就是说,由于 applet 程序试 图在没有获得正确的权限的情况下访问系统资源,所以生成了该栈跟踪。其第二 行代码表示,若要纠正这种情况,您需要一个向数据库所在计算机(developer) 授予 applet 访问权限的 SocketPermission

您可以利用 Policy 工具生成您所需要的策略文件,或者用一个 ASCII 编辑 器生成该策略文件。以下为具有栈跟踪指示的权限的策略文件:

grant {
  permission java.net.SocketPermission "developer", 
    "resolve";
  "accessClassInPackage.sun.jdbc.odbc";
};

再次运行 applet 程序,这次运行加上了名为 DbaApplPol 的、 获得上述权限的策略文件:

appletviewer -J-Djava.security.policy=DbaApplPol 
                                       DbaAppl.html

运行完毕后,您同样会得到一个栈跟踪,只不过这次的出错情况不一样。

  java.security.AccessControlException: access denied 
  (java.net.SocketPermission
  129.144.176.176:1521 connect,resolve)

现在,您需要一个允许在数据库所在的 developer 计算机上访 问国际互联网协议(IP)地址和端口的 SocketPermission

以下是获得并添加了栈跟踪所指示的权限的 DbaApplPol 策略 文件:

grant {
  permission java.net.SocketPermission "developer", 
                       "resolve";
  permission java.net.SocketPermission 
  "129.144.176.176:1521", "connect,resolve";
};

重新运行 applet 程序。如果您使用含有已指定 Socket 权限的策略文件,程 序就会成功运行。

  appletviewer -J-Djava.security.policy=DbaApplPol 
                                         DbaAppl.html

ODBC 驱动程序与 JDBC-ODBC 的桥接

开放式数据库连接(ODBC)是微软公司用于访问各种平台上的多种关系数据库 的程序接口。JDBC-ODBC 桥接内置于 Solaris 和 Windows 版 Java 平台中,这 样您可以完成两件事:

  1. 通过 Java 程序加载 ODBC
  2. 把 ODBC 驱动程序作为 JDBC 驱动程序加载。本例采用 JDBC-ODBC 桥接加 载 ODBC 驱动程序,以连接到数据库。然而,applet 程序没有 ODBC 程序代 码。

DriverManager利用环境设置值来查找并加载数据库驱动程序。 对本例而言,驱动程序文件并不需要在本地访问。

启动 Applet 程序:以下是运行 DbaOdbAppl applet 程序的 DbaOdb.html 文件:

<HTML>
<BODY>

<APPLET CODE=DbaOdbAppl.class 
  WIDTH=200 
  HEIGHT=100>
</APPLET>

</BODY>
</HTML>

启动 applet 程序的代码是:

  appletviewer DbaOdb.html

读栈跟踪:如果 DbaOdbAppl.java applet 程序运行但没有策略文件,那么在终端用户点击 Click Me 按钮时生成以下栈跟踪:

  java.security.AccessControlException: access denied
  (java.lang.RuntimePermission 
  accessClassInPackage.sun.jdbc.odbc )

上述栈跟踪的第一行代码通知您访问被拒绝。这就是说,由于 applet 程序试 图访问系统资源,但却没有获得正确的权限,所以生成了该栈跟踪。其第二行代 码表示,若要纠正这种情况,您需要一个授予 applet 向 sun.jdbc.odbc 程序包 访问的 RuntimePermission 权限。该程序包为 Java1 虚拟机(VM)提供了 sun.jdbc.odbc 桥接功能。

您可以利用 Policy 工具生成您所需要的策略文件,或者用一个 ASCII 编辑器 生成该策略文件。以下为具有栈跟踪指示的权限的策略文件:

grant {
  permission java.lang.RuntimePermission
    "accessClassInPackage.sun.jdbc.odbc";
};

再次运行 applet 程序,这次运行加上了名为 DbaOdbPol 的、 获得上述权限的策略文件:

  appletviewer -J-Djava.security.policy=DbaOdbPol 
                                         DbaOdb.html

运行完毕后,您同样会得到一个栈跟踪,只不过这次的出错情况不一样。

  java.security.AccessControlException:
  access denied (java.lang.RuntimePermission
  file.encoding read)

栈跟踪表示,applet 程序需要有读取编码文件(二进制文件)的权限。以下 为带有栈跟踪指定权限的 DbaOdbPol 策略文件:

  grant {
    permission java.lang.RuntimePermission
       "accessClassInPackage.sun.jdbc.odbc";
    permission java.util.PropertyPermission
       "file.encoding", "read";
  };

重新运行 applet 程序。如果采用了带有指定运行时和属性权限的上述策略文 件,程序就能够成功运行。

  appletviewer -J-Djava.security.policy=DbaOdbPol 
                                         DbaOdb.html

Servlet 程序对数据库的访问

正如您在第 6 课中所学的一样,servlet 受运行它们的Web服务器的安全策略 所管辖。当把数据库读和写代码添加到第 6 课中的 FileIOServlet 中时,本课中的 DbaServlet.java servlet 程序将在 Java WebServerTM 1.1.1 下无限制地 执行。

Web服务器必须经过配置来定位数据库。若要寻求相应的帮助,请查阅您的Web 服务器文档或咨询数据库管理员。采用 Java WebServer 1.1.1 时,配置设置的 内容包括:编辑带有环境设置值的启动程序脚本,如加载 ODBC 驱动程序、定位 并连接到数据库等。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import java.sql.*;
import java.net.*;
import java.io.*;

public class DbaServlet extends HttpServlet {

 private Connection c;
 final static private String _driver = 
	"sun.jdbc.odbc.JdbcOdbcDriver";
 final static private String _user = "username";
 final static private String _pass = "password";
 final static private String 
			_url = "jdbc:odbc:jdc";

public void doPost(HttpServletRequest request,
	HttpServletResponse response)
	throws ServletException, IOException{
  response.setContentType("text/html");
  PrintWriter out = response.getWriter();
  out.println("<title>Example<title>" +
      "<body bgcolor=FFFFFF>");

  out.println("<h2>Button Clicked</h2>");

  String DATA = request.getParameter("DATA");

  if(DATA != null){
     out.println("<STRONG>Text from 
			form:</STRONG>");
     out.println(DATA);
  } else {
    out.println("No text entered.");
  }

//Establish database connection
  try{
    Class.forName (_driver);
    c = DriverManager.getConnection(_url, 
				    _user,
				    _pass);
   } catch (Exception e) {
     e.printStackTrace();
     System.exit(1);
   }

   try{
//Code to write to database
     Statement stmt = c.createStatement();
     String updateString = "INSERT INTO dba " + 
		"VALUES ('" + DATA + "')";
     int count = stmt.executeUpdate(updateString);

//Code to read from database
     ResultSet results = stmt.executeQuery(
		"SELECT TEXT FROM dba ");
     while(results.next()){
       String s = results.getString("TEXT");
       out.println("<BR>
         <STRONG>Text from database:</STRONG>");
       out.println(s);
     }
      stmt.close();
     }catch(java.sql.SQLException e){
      System.out.println(e.toString());
     }

      out.println("<P>Return to 
        <A HREF="../dbaHTML.html">Form</A>");
      out.close();
  }
}

更多信息

Java 教程 对象和类 中,您会发现有关变量访问设置值的更多信息。


1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

[TOP]

 

常见问答
下载中心
产品简介
 
 
Solaris论坛
 
   
 
null