使用 JDBC 创建数据库对象 2

原创 2001年05月04日 13:45:00

构建更高级别的 JDBC 对象

从上面的例子可以明显看出,如果可以将我们使用过的一些方法封装在几个更高级别对象中,那将非常有帮助,我们不仅可以封装 try 程序块,而且可以更简单地访问 ResultSet 方法。

在这一部分中,我们将构建一个新的 resultSet 对象,该对象封装了 JDBC ResultSet 对象,并以 String 数组的形式返回一行数据。我们发现您始终需要从 ResultSetMetaData 对象中获取列的序号和名称,因此,创建一个封装元数据的新对象就非常合理。

另外,我们经常需要按名称或整数索引提取某行的元素,如果不必总是将这些访问语句包括 try 块中,那将大有帮助。最后一点,如果我们需要整行的内容,则更方便的做法是将整行以String 数组形式返回。在下面所示的 resultSet 对象中,我们致力于实现这些目标:

class resultSet
{
//这个类是 JDBC ResultSet 对象的更高级抽象
   ResultSet rs;
   ResultSetMetaData rsmd;
   int numCols;
   public resultSet(ResultSet rset)
   {
      rs = rset;
      try
      {
      //同时获取元数据和列数
      rsmd = rs.getMetaData();
      numCols = rsmd.getColumnCount();
      }
      catch (Exception e)
      {System.out.println("resultset error"
                                +e.getMessage());}
   }
   //--
   public String[] getMetaData()
   {
    //返回包含所有列名或其他元数据的
    //一个数组
      String md[] = new String[numCols];
      try
         {
      for (int i=1; i<= numCols; i++) 
         md[i-1] = rsmd.getColumnName(i);
      }
      catch (Exception e)
      {System.out.println("meta data error"+
                                e.getMessage());}
      return md;
   }
   //--
   public boolean hasMoreElements()
   {
      try{
      return rs.next();
      }
   catch(Exception e){return false;}
   }
   //--
   public String[] nextElement()
   {
   //将行的内容复制到字符串数组中
      String[] row = new String[numCols];
      try
      {
      for (int i = 1; i <= numCols; i++) 
            row[i-1] = rs.getString(i);
      }
      catch (Exception e)
      {System.out.println("next element error"+
                        e.getMessage());}
    return row;
   }
   //--
   public String getColumnValue(String columnName)
   {
   String res = "";
     try 
     {
     res = rs.getString(columnName);
     }
   catch (Exception e)
   {System.out.println("Column value error:"+
                columnName+e.getMessage());}
   return res;
   }
   //--
   public String getColumnValue(int i)
   {
   String res = "";
     try 
     {
     res = rs.getString(i);
     }
   catch (Exception e)
   {System.out.println("Column value error:"+
                columnName+e.getMessage());}
   return res;
   }
   //--
   public void finalize()
   {
    try{rs.close();}
    catch (Exception e)
      {System.out.println(e.getMessage());}
   }
}
通过简单使用 new 操作符就地创建一个 ResultSet 对象,我们很容易将任何 ResultSet 对象封装在此类中:
ResultSet results = ..  //按通常的方法获得ResultsSet
//利用它创建一个更有用的对象
resultSet rs = new resultSet(results);
并很容易在任何 JDBC 程序中使用这个对象。

构建一个 Database 对象

我们沿 00 链向上移的另一部分努力是创建一个 Database 对象,它将封装下列对象的行为:ConnectionStatement DatabaseMetaData 对象, 以及我们刚刚构建的 SQL 查询和 resultSet。我们的 Database 对象允许我们创建连接、获取表名、在数据库中移动以及更简单地获得行和列的值。请注意,Execute 方法返回一个 resultSet 对象,您可以直接对它进行操作。
class Database
{
//这是一个将 JDBC 数据库的所有功能封装在单个对象中的类
Connection con;
resultSet results;
ResultSetMetaData rsmd;
DatabaseMetaData dma;
String catalog;
String types[];
   public Database(String driver)
   {
    types = new String[1];
    types[0] = "TABLES";         //初始化类型
    try{Class.forName(driver);}  //加载 JDBC-ODBC 桥驱动程序
    catch (Exception e)
    {System.out.println(e.getMessage());}
   }
   //--
   public void Open(String url, String cat)
   {
    catalog = cat;
    try {con = DriverManager.getConnection(url);
    dma =con.getMetaData();   //获取元数据
    }
    catch (Exception e)
    {System.out.println(e.getMessage());}
   }
   //--
   public String[] getTableNames()
   {
    String[] tbnames = null;
    Vector tname = new Vector();
    //将表名添加到一个 Vector 中,
    //因为我们不知道有多少个表
    try {
      results = 
                new resultSet(dma.getTables(catalog, null, 
                        "%", types));
      
      while (results.hasMoreElements())
         tname.addElement(results.getColumnValue("TABLE_NAME"));
      
      }
     catch (Exception e) {System.out.println(e);}
     //将表名复制到一个 String 数组中
      tbnames = new String[tname.size()];
      for (int i=0; i< tname.size(); i++) 
         tbnames[i] = (String)tname.elementAt(i);
      return tbnames;
   }
   //--
   public String[] getTableMetaData()
   {
      // 返回表类型的信息
      results = null;
      try{
      results = 
                new resultSet(dma.getTables(catalog, null, 
                        "%", types));
      }
      catch (Exception e)
      {System.out.println(e.getMessage());}
      return results.getMetaData();
   }
   //--
   public String[] getColumnMetaData(String tablename)
   {
    //返回一个列的数据
    results = null;
    try {
    results = 
                new resultSet(dma.getColumns(catalog, null, 
                        tablename, null));
    }
    catch (Exception e)
   {System.out.println(e.getMessage());}
    return results.getMetaData();
   }
   //--
   public String[] getColumnNames(String table)
   {
   //返回一个列名数组
   String[] tbnames = null;
   Vector tname = new Vector();
   try {
   results = 
                new resultSet(dma.getColumns(catalog, null, 
                        table, null));
    while (results.hasMoreElements() )
       tname.addElement(results.getColumnValue("COLUMN_NAME"));  
      }
   catch (Exception e) {System.out.println(e);}
   tbnames = new String[tname.size()];
   for (int i=0; i< tname.size(); i++) 
      tbnames[i] = (String)tname.elementAt(i);
   return tbnames;
   } 
//--
public String getColumnValue(String table, 
                        String columnName)
   {
   //返回给定列的值 
   String res = null;
   try 
     {
      if (table.length()>0) 
         results =
                         Execute("Select " + columnName +
                                " from " + table + 
                                " order by "+columnName);
      if (results.hasMoreElements())
         res = results.getColumnValue(columnName);
     }
   catch (Exception e)
   {System.out.println("Column value error" +
                columnName+ e.getMessage());}
   return res;
   }
//--
   public String getNextValue(String columnName)
   {
   // 使用存储的 resultSet
   //返回该列的下一个值
      String res = "";
   try 
     {
      if (results.hasMoreElements())
         res = results.getColumnValue(columnName);
     }
   catch (Exception e)
   {System.out.println("next value error"+
                columnName+ e.getMessage());}
   return res;
 }
//--
   public resultSet Execute(String sql)
   {
   //对此数据库执行一个 SQL 查询
   results = null;
   try
      {
      Statement stmt = con.createStatement();
      results = new resultSet(stmt.executeQuery(sql));
    }
    catch (Exception e)
      {System.out.println("execute error"+
                e.getMessage());}
   return results;
   }
}

一个可视化的数据库程序

为了对我们本章学习的内容进行总结,我们编写一个简单的 GUI 程序,它可以显示数据库的表名、列名和列内容。我们还将包括一个文本区域,您可以在其中键入一个要对数据库执行的 SQL 查询。在 Companion CD-ROM 上的 /chapter20 子目录中,可以找到本程序(称为 dbFrame.java)所使用的 resultSet Database 类。程序的显示界面如图 3 所示。

数据库图示
3:用来显示用 JDBC 连接的数据库中的数据的 dbFrame.java 程序。

在本程序中,默认数据库 (groceries.mdb) 的表名显示在左侧的栏中。当您单击其中一个表名时,列名就会显示在中间的栏中。最后,当您单击中间栏中的某一行时,该行的内容就会显示在右侧的栏中。

本程序的关键只是接收列表选择,然后清除并填充正确的列表框:

public void itemStateChanged(ItemEvent e)
   {
      Object obj = e.getSource();
      if (obj == Tables)     //放入列名
         showColumns();
      if (obj == Columns)    //放入列的内容
         showData();
   }
//--
   private void loadList(List list, String[] s)
   {
        //清除并填充指定的列表框
    list.removeAll();
    for (int i=0; i< s.length; i++)
         list.add(s[i]);
   }
   //--
   private void showColumns()
   {
        //显示列名
        String cnames[] = 
                db.getColumnNames(Tables.getSelectedItem());
      loadList(Columns, cnames);
   }
   //--
   private void showData()
   {
      String colname = Columns.getSelectedItem();
      String colval = 
                db.getColumnValue(Tables.getSelectedItem(), 
                        colname);
      Data.setVisible(false);
      Data.removeAll();
      Data.setVisible(true);
      colval = 
                        db.getNextValue(Columns.getSelectedItem());
      while (colval.length()>0) 
         {
         Data.add(colval);
         colval = 
                        db.getNextValue(Columns.getSelectedItem());
         }
   }
执行查询
显示画面底部的文本区域使您可键入所需的任何 SQL 查询。演示程序中构建的一个查询如下所示:
String queryText =
"SELECT DISTINCTROW FoodName, StoreName, Price "+
"FROM (Food INNER JOIN FoodPrice ON "+
"Food.FoodKey = FoodPrice.FoodKey) " +
"INNER JOIN Stores ON "+
"FoodPrice.StoreKey = Stores.StoreKey "+
"WHERE (((Food.FoodName)=/'Oranges/')) "+
" ORDER BY FoodPrice.Price;";
此查询简单地列出每个杂货店的桔子价格。

当您单击 Run Query 按钮时,它将执行此查询,并将 resultSet 对象传送给一个对话框进行显示:

public void actionPerformed(ActionEvent e)
   {
      Object obj = e.getSource();
      if (obj == Quit) 
         System.exit(0);
      if (obj == Search) 
         clickedSearch();
   }
//--
   private void clickedSearch()
   {
      resultSet rs = db.Execute(query.getText());
      String cnames[] = rs.getMetaData();
    
      queryDialog q = new queryDialog(this, rs);
      q.show();
   }
查询结果对话框
查询对话框获得 resultSet 对象,并将每一行放入一个 String 数组中,然后将这些 String 数组放入一个 Vector 中,这样就可以在 paint() 子程序运行期间快速访问这些行。
private void makeTables()
{
//将每一行放入一个 String 数组中,并将
//这些字符串数组全部放入一个 Vector    tables = new Vector();
   String t[] = results.getMetaData();
   tables.addElement( t);
   while (results.hasMoreElements()) 
                tables.addElement(results.nextElement());
   }
我们通过 Graphics drawString() 方法将数据绘制在一个 Panel 中。就像在 Printer 对象中一样,我们必须自己跟踪 x y 的位置。
public void paint(Graphics g)
{
 String s[];
 int x=0;
//计算字体的高度
 int y =g.getFontMetrics().getHeight();
//估算列的高度
 int deltaX = (int)1.5f*
  (g.getFontMetrics().stringWidth("wwwwwwwwwwwwww"));
//遍历表矢量
 for (int i=0; i< tables.size(); i++) 
   {
   s  = (String[])tables.elementAt(i);
        //绘制字符串数组中的每一行
   for (int j =0; j< s.length; j++) 
    {
    String st= s[j];
    g.drawString(st, x, y);
    x += deltaX;           //移到下一列
    }
   x = 0;                 //开始一个新行
   y += g.getFontMetrics().getHeight();
        //列标签与列数据之间的额外空间
   if (i == 0) y += g.getFontMetrics().getHeight();
   }
}
内建查询的 queryDialog 如图 4 所示。

查询结果
4dbFrame 程序中 显示的 queryDialog,其中显示的是默认查询的结果。

示例文件

groceries.zip
dbFrame.zip
jdbc-odbc Bridge

小结

在本文中,我们讨论了数据库以及检验数据库并对数据库执行查询的方法。我们已经看到,JDBC 提供了一种与平台和数据库无关的、面向对象的方法来访问这些数据,我们还学习了 JDBC 的主要对象:ResultSetResultSetMetaData DatabaseMetaData在用这些对象编写了一个简单的程序之后,我们设计了更高级别的 resultSet Database 对象,我们用它们构建了一个简单的可视化界面来显示数据库信息。

如果您熟悉数据库的强大功能,就会认识到 SQL 语言可使您执行比我们此处所述操作更强大的任务。例如,您可以创建新表、添加、更改或删除表的行、列或单个表元。使用 JDBC,所有这一切都变得通用和易于处理。

如果您使用的是特定平台的数据库驱动程序,如 JDBC-ODBC Bridge,则您在编写应用程序时会受到限制,因为 applet 不能连接在另一台计算机上运行的这个桥。其他客户机-服务器数据库,如 IBM DB2,允许您使用 applet 中的 JDBC 与其连接。


使用 JDBC 创建数据库对象

立...
  • lwqadmin
  • lwqadmin
  • 2004年10月18日 18:18
  • 737

使用 JDBC 创建数据库对象 1

  • zgqtxwd
  • zgqtxwd
  • 2008年04月25日 21:06
  • 259

JDBC-创建数据库

JDBC创建数据库   在执行下面的例子前,请确保有以下: 必须具有管理员权限才能在给定的模式创建一个数据库。要执行下面的示例中,需要更换实际用户名和密码,用户名和密码。 MySQL数据库正在启动和...
  • qq_35448976
  • qq_35448976
  • 2017年05月10日 11:47
  • 3036

【SQLite入门】使用SQLite、创建数据库、创建表、使用Jdbc连接SQLite

有关SQLite3使用: 1.将sqlite3.exe文件放在任何位置(本人放在E:\SQLite). 2.在cmd下进入到E:\SQLite下(cd E:\SQLite). 3.在cmd...
  • YoungStar70
  • YoungStar70
  • 2017年05月30日 22:59
  • 717

通过反射+注解+JDBC创建数据库表

反射+注解+JDBC创建数据库表本次实例我们讲解一个数据库框架的小案例,这里我只写了一个功能,还有关其他数据库操作的功能我会再后面填写上。功能介绍: 通常我们对数据库进行操作时,都需要创建一个表,在没...
  • qq_27630169
  • qq_27630169
  • 2016年07月30日 09:53
  • 1220

JDBC那些事(三)——PreparedStatement预编译对象

“PreparedStatement 接口继承了Statement,并与之在两方面有所不同:有人主张,在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替...
  • u010377383
  • u010377383
  • 2017年01月19日 13:49
  • 299

JDBC的几个常用对象

JDBC中常见的对象,实现与业务逻辑层的交互  1、Connection对象:  *Connection conn = DriverMananger.getConnection(url,usern...
  • sujianxin2012
  • sujianxin2012
  • 2014年09月03日 22:12
  • 715

jdbc的con、pstmt、rs的非正常关闭顺序探讨

首先大家都知道,正常的关闭顺序都是ResultSet、PreparedStatement、Connection的顺序,这里就不作讨论了 Connection:与特定数据库的连接(会话)。 Prep...
  • wxwzy738
  • wxwzy738
  • 2012年08月03日 10:25
  • 6154

JDBC之beanUtils的基本使用

@Test public void test1() throws Exception { //a. BeanUtils组件实现对象属性的拷贝 /*Admin admin = new Admin...
  • Tomsheng321
  • Tomsheng321
  • 2017年01月28日 12:39
  • 179

JDBC中常用对象介绍

JDBC常用对象的介绍
  • qq_25827845
  • qq_25827845
  • 2016年09月18日 19:26
  • 3107
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用 JDBC 创建数据库对象 2
举报原因:
原因补充:

(最多只允许输入30个字)