JDBC快速入门

• 本文讲述JDBC(Java Database Connectivity) API(Application Program Interface) 的基本操作。读完本篇后,您将学会如何使用JDBC API建表、插入数值、查询、检索结果、修改表属性及内容、建立填充语句(prepared statements)、事物处理(perform transactions)和捕捉异常与错误。
________________________________________
概要
JDBC接口允许外部对SQL数据库进行管理以及对内容进行修改操作。通过使用第三方驱动,它们允许使用SQL语句调用。而且,Java内建的JDBC具有丰富的指令集合,使用起来相当的简单和直观。
举个例子:您正着手写一个Java程序,需要用到与数据库交互的操作。您得使用标准库提供的指令(方法)。首先建立一个数据库的连接。然后,您使用JDBC向数据库传送SQL语句,再处理返回的结果。最后关闭数据库的连接。
________________________________________
建立连接
我要从什么地方下手呢?当然了,要先在您的机器上安装Java、JDBC和DBMS(数据库)。由于我想使用Oracle数据,所以我需要找到指定的驱动。先到Oracle官方网址看看,真的有,下载地址: http://www.oracle.com/technology/global/cn/software/tech/java/sqlj_jdbc/index.html
正如先前所说,在对数据库操作(access)之前,必须在程序(client)与数据库(server)之间建立一个连接。
• 加载指定的第三方驱动
为何要来这一手呢?为使操作更轻便、代码复用程度更高,API常被尽可能地设计成与版本及厂商无关。由于不同的关系型数据库具有不同的形为,我们得告诉所用的驱动,这样它们才能做出正确的行为。
下面是加载Oracle驱动的代码:
      Class.forName("oracle.jdbc.driver.OracleDriver")
• 建立连接
一旦驱动被加载并处于准备连接状态,您就可以使用下面的代码建立一个连接实例:
   Connection con = DriverManager.getConnection(
      "jdbc:oracle:thin:@dbaprod1: 1521:orcl", username, passwd);
好,让我们一起来弄懂这里用到的术语吧。第一个字符串(string)是一个数据库的URL,包括协议(jdbc), 厂商(oracle), 驱动(thin), 服务器(dbaprod1), 端口号 (1521), 和服务器实例(orcl) 。数据库连接的用户名和密码分别为: username、 passwd。
完了。最后一步返回的是一个打开的连接,用来传送SQL语句与数据库进行交互操作。在上面的代码中,con就是这样的一个连接,稍后我们会用到。(注:上面代码所示范的,很可能会与您的环境不一致,请依照您的环境作必要的修改)
________________________________________
建立JDBC语句(Statement)
JDBC语句用于向数据库传送SQL语句。JDBC语句不同于SQL语句,它是与数据库连接密切相关的,不单是一个SQL语句。您可以把JDBC想象成一个道往数据库的通道,用来传送一个或多个SQL语句到数据库中。
一个活动连接需要建立一个 Statement 对象。示范如下(用到先前建立的Connection 对象con):
    Statement stmt = con.createStatement() ;
到此,一个Statement 对象已经存在,还差一个传送到数据库的SQL语句,下面就学到。
________________________________________
建立JDBC填充语句(PreparedStatement)
有时候,使用PreparedStatement对象向数据库传送SQL语句更加方便而且更有效率。有别于它的父类Statement,它只在创建的时候被赋予一个SQL语句。该条SQL语句被传送到数据库时,立刻被编译。因此,PreparedStatement语句直接绑定于通道和被编译的SQL语句上。
优点显而易见:如果您需要使用多个相同或相似的SQL语句(仅其中的参数不同),使用PreparedStatement只需要被编译一次并被优化。使用普通的Statement就需要多次并且是逐个地被编译。
PreparedStatements 同样使用Connection 的方法建立。下面的代码示范如何建立一个填充语句,并且带有三个参数。
   PreparedStatement prepareUpdatePrice = con.prepareStatement(
      "UPDATE Sells SET price = ? WHERE bar = ? AND beer = ?");
在执行PreparedStatement之前,我们需要提供相应的值去填充这些参数。这需要用到PreparedStatement类中的setXXX方法。常用的方法有:setInt, setFloat, setDouble, setString等。
接着上面的示例:
   prepareUpdatePrice.setInt(1, 3);
   prepareUpdatePrice.setString(2, "Bar Of Foo");
   prepareUpdatePrice.setString(3, "BudLite");
________________________________________
执行 CREATE/INSERT/UPDATE 语句
DDL (data definition language) 语句,如建表,修改表结构,更新表内容都可以使用executeUpdate方法。示范如下:
   Statement stmt = con.createStatement();

   stmt.executeUpdate("CREATE TABLE Sells " +
      "(bar VARCHAR2(40), beer VARCHAR2(40), price REAL)" );
   stmt.executeUpdate("INSERT INTO Sells " +
      "VALUES ('Bar Of Foo', 'BudLite', 2.00)" );

   String sqlString = "CREATE TABLE Bars " +
      "(name VARCHAR2(40), address VARCHAR2(80), license INT)" ;
   stmt.executeUpdate(sqlString);
由于SQL语句并非恰好为一个字符串(或适合写在一行),所以需要使用加号(+)连结。特别注意在字符串"INSERT INTO Sells"后面的空格,为的是与字符串"VALUES"分开。
当使用executeUpdate执行DDL语句,返回值总是零(zero),当执行数据修改语句时将返回大于等零的值,即被修改的记录数。
      int n = prepareUpdatePrice.executeUpdate() ;
________________________________________
执行 SELECT 语句
相对于前面的执行语句(DDL),查询语句执行后返回一个结果集合,并且不改变数据库的状态。相应地使用另一个方法executeQuery,返回一个ResultSet对象:
   String bar, beer ;
   float price ;

   ResultSet rs = stmt.executeQuery("SELECT * FROM Sells");
   while ( rs.next() ) {
      bar = rs.getString("bar");
      beer = rs.getString("beer");
      price = rs.getFloat("price");
      System.out.println(bar + " sells " + beer + " for " + price + " Dollars.");
   }
查询语句返回的结果集被放在一个ResultSet实例中。我们可以访问结果集中的每一行记录(record)及每一行记录的属性。ResultSet提供一个游标(cursor),用于访问它的每一行记录。游标开始时指示在第一条记录的前面。可以使用next方法使游标指向下一条记录,如果下一条记录存在,next方法返回真(true),否则返回假(false)。
我们可以使用相应类型的getXXX方法获取某一行记录。在前面的示例中,我们用的是getString和getFloat方法访问某一列的值。我们需要提供列的名称作为方法的参数,并且注意VARCHAR2类型的bar、beer被转换成Java的String、REAL被转换成Java的float。
我们还可以使用列的顺序号代替列的名称来访问结果集,示范如下:
      bar = rs.getString(1);
      price = rs.getFloat(3);
      beer = rs.getString(2);
________________________________________
访问ResultSet
JDBC还提供一套方法,让您得到游标当前处于结果集的位置,如getRow, isFirst, isBeforeFirst, isLast, isAfterLast。
这意味着游标允许自由访问结果集。默认的,游标只能向前滚动并且是只读的。当连接(Connection)建立了语句(Statement)后,您可以灵活地改变结果集(ResultSet)的滚动及更新模式。
      Statement stmt = con.createStatement(
         ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
      ResultSet rs = stmt.executeQuery("SELECT * FROM Sells");
不同的选项包括: TYPE_FORWARD_ONLY、TYPE_SCROLL_INSENSITIVE和TYPE_SCROLL_SENSITIVE。您可以在需要只读游标时选用CONCUR_READ_ONLY、需要更新时选用CONCUR_UPDATABLE。默认的游标可以使用rs.next()向前滚动。使用可滚动的游标,您有更多的操作,示范如下:
      rs.absolute(3);          // 滚动到结果集的第三行
      rs.previous();           // 回滚一行(第二行)
      rs.relative(2);          // 向前滚动两行(第四行)
      rs.relative(-3);         // 回滚三行(第一行)
________________________________________
事务(Transactions)
JDBC允许多条SQL语句作为一个事务。因此使用JDBC事务,我们能确保ACID (Atomicity, Consistency, Isolation, Durability)属性。
连接建立后,默认的事务模式是自动提交(auto-commit)。这使每一条SQL语句都被当作一个事务来处理。
我们可以关闭自动提交事务模式,如下:
      con.setAutoCommit(false) ;
再次打开自动提交事务模式:
      con.setAutoCommit(true) ;
一旦自动提交模式被关闭,除非您明确地使用commit()方法提交,否则每一条SQL语句都不会被提交。
      con.commit() ;
在执行commit()方法之前,我们可以随时使用rollback()方法来回滚事务,取消之前的操作。
举例如下:
      con.setAutoCommit(false);
      Statement stmt = con.createStatement();
      stmt.executeUpdate("INSERT INTO Sells VALUES('Bar Of Foo', 'BudLite', 1.00)" );
      con.rollback();
      stmt.executeUpdate("INSERT INTO Sells VALUES('Bar Of Joe', 'Miller', 2.00)" );
      con.commit();
      con.setAutoCommit(true);
请读者逐句理解上面的例子吧。
通常,事务回滚结合Java异常机制,被用于处理(不)可预见的错误。下一节我们将介绍Java的异常机制。
________________________________________
Handling Errors with Exceptions
错误无处不在。为保证程序的可恢复性,让数据库不至于由于某个错误导致崩溃。事务回滚与Java的异常机制提供了很优雅的解决办法。
客户(program)访问服务器(database)需要获得服务器的任务错误反馈。JDBC提供了SQLException用于访问这些错误。
结束事务回滚,举一个异常的例子:
      try {
         con.setAutoCommit(false) ;
         stmt.executeUpdate("CREATE TABLE Sells (bar VARCHAR2(40), " +
                            "beer VARHAR2(40), price REAL)") ;
         stmt.executeUpdate("INSERT INTO Sells VALUES " +
                            "('Bar Of Foo', 'BudLite', 2.00)") ;
         con.commit() ;
         con.setAutoCommit(true) ;

      }catch(SQLException ex) {
         System.err.println("SQLException: " + ex.getMessage()) ;
         con.rollback() ;
         con.setAutoCommit(true) ;
      }
在上例中,由于beer被定义为VARHAR2(拼写错误),导致一个异常被抛出。错误的输出如下:
      Message:  ORA-00902: invalid datatype
假如您纠正了数据类型的错误,也可能会发生空间不足的错误,使您不能够建立一个新表。

需要对照原文,请访问:http://www-db.stanford.edu/~ullman/fcdb/oracle/or-jdbc.html

你可能感兴趣的:(数据结构,oracle,sql,jdbc,SQL Server)