內(nèi)蒙古java團(tuán)隊(duì)

          j2se,j2ee開發(fā)組
          posts - 139, comments - 212, trackbacks - 0, articles - 65
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          全面解析JDBC <二>

          Posted on 2007-11-21 18:23 帥子 閱讀(201) 評(píng)論(0)  編輯  收藏 所屬分類: J2EE技術(shù)專區(qū)
          下面的代碼演示了一種方法用來確認(rèn)已訪問調(diào)用方法execute所產(chǎn)生的全部結(jié)果集和更新計(jì)數(shù):

          stmt.execute(queryStringWithUnknownResults);
          while(true){
          introwCount=stmt.getUpdateCount();
          if(rowCount>0){//它是更新計(jì)數(shù)
          System.out.println("Rows changed="+count);
          stmt.getMoreResults();
          continue;
          }
          if(rowCount==0){//DDL命令或0個(gè)更新
          System.out.println("No rows changed or statement was DDL command");
          stmt.getMoreResults();
          continue;
          }
          //執(zhí)行到這里,證明有一個(gè)結(jié)果集
          //或沒有其它結(jié)果
          ResultSet rs=stmt.getResultSet();
          if(rs!=null){
          ...//使用元數(shù)據(jù)獲得關(guān)于結(jié)果集列的信息
          while(rs.next()){
          ...//處理結(jié)果
          stmt.getMoreResults();
          continue;
          }
          break;//沒有其它結(jié)果 
          如何獲得SQL語句的執(zhí)行結(jié)果?

            ResultSet包含符合SQL語句中條件的所有行,并且它通過一套get方法(這些get方法可以訪問當(dāng)前行中的不同列)提供了對(duì)這些行中數(shù)據(jù)的訪問。ResultSet.next方法用于移動(dòng)到ResultSet中的下一行,使下一行成為當(dāng)前行。

            下面的代碼段是執(zhí)行SQL語句的示例。該SQL語句將返回行集合,其中列1為int,列2為String,而列3則為字節(jié)數(shù)組:

          Java.sql.Statementstmt=conn.createStatement();
          ResultSet r=stmt.executeQuery("SELECT a,b,c FROM Table1");
          while(r.next()){
          //打印當(dāng)前行的值。
          Int i=r.getInt("a");
          String s=r.getString("b");
          Float f=r.getFloat("c");
          System.out.println("ROW="+i+" "+s+" "+f);


            1. 行和光標(biāo)

            ResultSet維護(hù)指向其當(dāng)前數(shù)據(jù)行的光標(biāo)。每調(diào)用一次next方法,光標(biāo)向下移動(dòng)一行。 

            最初它位于第一行之前,因此第一次調(diào)用next將把光標(biāo)置于第一行上,使它成為當(dāng)前行。隨著每次調(diào)用next導(dǎo)致光標(biāo)向下移動(dòng)一行,按照從上至下的次序獲取ResultSet行。

            在ResultSet對(duì)象或其父輩Statement對(duì)象關(guān)閉之前,光標(biāo)一直保持有效。在SQL中,結(jié)果表的光標(biāo)是有名字的。如果數(shù)據(jù)庫允許定位更新或定位刪除,則需要將光標(biāo)的名字作為參數(shù)提供給更新或刪除命令。可通過調(diào)用方法getCursorName獲得光標(biāo)名。

            DatabaseMetaData.supportsPositionedDelete和supportsPositionedUpdate方法來檢查特定連接是否支持這些操作。當(dāng)DBMS支持定位更新和刪除操作時(shí),DBMS/驅(qū)動(dòng)程序必須確保適當(dāng)鎖定選定行,以使定位更新不會(huì)導(dǎo)致更新異常或其它并發(fā)問題。

            2. 列

            方法getXXX提供了獲取當(dāng)前行中某列值的途徑。在每一行內(nèi),可按任何次序獲取列值。但為了保證可移植性,應(yīng)該從左至右獲取列值,并且一次性地讀取列值。

            列名或列號(hào)可用于標(biāo)識(shí)要從中獲取數(shù)據(jù)的列。例如,如果ResultSet對(duì)象rs的第二列名為"title",并將值存儲(chǔ)為字符串,則下列任一代碼將獲取存儲(chǔ)在該列中的值:

            String s=rs.getString("title");
            String s=rs.getString(2);

            注意列是從左至右編號(hào)的,并且從列1開始。同時(shí),用作getXXX方法的輸入的列名不區(qū)分大小寫。

            提供使用列名這個(gè)選項(xiàng)的目的是為了讓在查詢中指定列名的用戶可使用相同的名字作為getXXX方法的參數(shù)。另一方面,如果select語句未指定列名(例如在"select * from table1"中或列是導(dǎo)出的時(shí)),則應(yīng)該使用列號(hào)。這些情況下,用戶將無法確切知道列名。

            有些情況下,SQL查詢返回的結(jié)果集中可能有多個(gè)列具有相同的名字。如果列名用作getXXX方法的參數(shù),則getXXX將返回第一個(gè)匹配列名的值。因而,如果多個(gè)列具有相同的名字,則需要使用列索引來確保檢索了正確的列值。這時(shí),使用列號(hào)效率要稍微高一些。

            關(guān)于ResultSet中列的信息,可通過調(diào)用方法ResultSet.getMetaData得到。返回的ResultSetMetaData對(duì)象將給出其ResultSet對(duì)象各列的編號(hào)、類型和屬性。

            如果列名已知,但不知其索引,則可用方法findColumn得到其列號(hào)。

            3. 數(shù)據(jù)類型和轉(zhuǎn)換

            對(duì)于getXXX方法,JDBC驅(qū)動(dòng)程序試圖將基本數(shù)據(jù)轉(zhuǎn)換成指定Java類型,

            然后返回適合的Java值。例如,如果getXXX方法為getString,而基本數(shù)據(jù)庫中數(shù)據(jù)類型為VARCHAR,則JDBC驅(qū)動(dòng)程序?qū)裋ARCHAR轉(zhuǎn)換成JavaString。getString的返回值將為JavaString對(duì)象。

            4. 對(duì)非常大的行值使用流
            ResultSet可以獲取任意大的LONGVARBINARY或LONGVARCHAR數(shù)據(jù)。方法getBytes和getString將數(shù)據(jù)返回為大的塊(最大為Statement.getMaxFieldSize的返回值)。但是,以較小的固定塊獲取非常大的數(shù)據(jù)可能會(huì)更方便,而這可通過讓ResultSet類返回Java.io.Input流來完成。從該流中可分塊讀取數(shù)據(jù)。注意:必須立即訪問這些流,因?yàn)樵谙乱淮螌?duì)ResultSet調(diào)用getXXX時(shí)它們將自動(dòng)關(guān)閉(這是由于基本實(shí)現(xiàn)對(duì)大塊數(shù)據(jù)訪問有限制)。

            JDBCAPI具有三個(gè)獲取流的方法,分別具有不同的返回值:

            ?getBinaryStream:返回只提供數(shù)據(jù)庫原字節(jié)而不進(jìn)行任何轉(zhuǎn)換的流。

            ?getAsciiStream返回提供單字節(jié)ASCII字符的流。

            ?getUnicodeStream返回提供雙字節(jié)Unicode字符的流。

            注意:它不同于Java流,后者返回?zé)o類型字節(jié)并可(例如)通用于ASCII和Unicode字符。下列代碼演示了getAsciiStream的用法:

          Java.sql.Statementstmt=con.createStatement();
          ResultSet r=stmt.executeQuery("SELECT x FROM Table2");
          //現(xiàn)在以4K塊大小獲取列1結(jié)果:
          byte buff=newbyte[4096];
          while(r.next()){
          Java.io.InputStream fin=r.getAsciiStream(1);
          for(;;){
          intsize=fin.read(buff);
          if(size==-1){//到達(dá)流末尾
          break;
          }
          //將新填充的緩沖區(qū)發(fā)送到ASCII輸出流:
          output.write(buff,0,size);
          }


            5. NULL結(jié)果值

            要確定給定結(jié)果值是否是JDBC NULL,必須先讀取該列,然后使用ResultSet.wasNull
          方法檢查該次讀取是否返回JDBC NULL。

            當(dāng)使用ResultSet.getXXX方法讀取JDBC NULL時(shí),方法wasNull將返回下列值之一:

            (1)Javanull值

            對(duì)于返回Java對(duì)象的getXXX方法(例如getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject等)。

            (2)零值:對(duì)于getByte、getShort、getInt、getLong、getFloat和getDouble。

            (3)false值:對(duì)于getBoolean。

            6. 可選結(jié)果集或多結(jié)果集

            通常使用executeQuery(它返回單個(gè)ResultSet)或executeUpdate(它可用于任何數(shù)據(jù)庫修改語句,并返回更新行數(shù))可執(zhí)行SQL語句。但有些情況下,應(yīng)用程序在執(zhí)行語句之前不知道該語句是否返回結(jié)果集。此外,有些已存儲(chǔ)過程可能返回幾個(gè)不同的結(jié)果集和/或更新計(jì)數(shù)。

            為了適應(yīng)這些情況,JDBC提供了一種機(jī)制,允許應(yīng)用程序執(zhí)行語句,然后處理由結(jié)果集和更新計(jì)數(shù)組成的任意集合。這種機(jī)制的原理是首先調(diào)用一個(gè)完全通用的execute方法,然后調(diào)用另外三個(gè)方法,getResultSet、getUpdateCount和getMoreResults。這些方法允許應(yīng)用程序一次一個(gè)地研究語句結(jié)果,并確定給定結(jié)果是ResultSet還是更新計(jì)數(shù)。

            用戶不必關(guān)閉ResultSet;當(dāng)產(chǎn)生它的Statement關(guān)閉、重新執(zhí)行或用于從多結(jié)果序列中獲取下一個(gè)結(jié)果時(shí),該ResultSet將被Statement自動(dòng)關(guān)閉。
           基于JDBC有哪些數(shù)據(jù)庫通用訪問方法?

            1. 通用數(shù)據(jù)庫Bean設(shè)計(jì)

            本實(shí)例中對(duì)數(shù)據(jù)庫連接和執(zhí)行SQL語句等通用數(shù)據(jù)庫操作進(jìn)行了封裝,通過實(shí)現(xiàn)DBConnBean和DBQueryBean兩個(gè)JavaBean來完成上述功能。其中DBConnBean負(fù)責(zé)Java應(yīng)用程序和數(shù)據(jù)庫的連接;DBQueryBean提供了一組執(zhí)行標(biāo)準(zhǔn)SQL的功能,可以實(shí)現(xiàn)標(biāo)準(zhǔn)SQL完成的所有功能。其功能代碼分別如下所示:

            ① DBConnBean.Java的源代碼如下所示:

          package dbaccess;
          import Java.sql.*;
          import Java.util.*;
          import Java.io.*; 
          public class DBConnBean 
          implements Serializable{

          private String DBDriver = "sun.jdbc.odbc.JdbcOdbcDriver";
          private String DBHost = "127.0.0.1";
          private String DBName = "demo";
          private String conp = "jdbc:odbc:db_demo";
          private String username = "";
          private String password = "";
          private boolean xdebug = true;

          public Connection con = null;

          public String sql = null;

          Statement stmt = null;
          public ResultSet result = null;
          private int affectedRows = 0;

          public DBConnBean()
          {
          xdebug = true;
          con = null;
          sql = null;
          }
          public Connection Connect() 
          throws Exception
          {
          String msg = null;
          try
          {
          Class.forName(DBDriver).newInstance(); 
          }
          catch(Exception e)
          {
          msg = "加載數(shù)據(jù)庫驅(qū)動(dòng)失敗";
          if (xdebug) msg += "(驅(qū)動(dòng)'"+DBDriver+"')";
          throw new Exception(msg);
          }
          try
          {
          String conStr = conp;
          con = DriverManager.getConnection(conStr,username,password);
          }
          catch(SQLException e)
          {
          msg = "!!數(shù)據(jù)庫連接失敗";
          if (xdebug)
          {
          msg += "(錯(cuò)誤信息='" + e.getMessage()+"' SQL狀態(tài)值='" + e.getSQLState()+"' 錯(cuò)誤代碼='" + e.getErrorCode()+"')";
          }
          throw new Exception(msg);
          }
          return con;
          }
          protected void finalize()
          throws Throwable
          {
          super.finalize();
          if (stmt != null) stmt.close();
          if (result != null) result.close();
          }
          //最近一次對(duì)數(shù)據(jù)庫查詢受影響的行數(shù)
          public int getAffectedRows()
          {
          return affectedRows;
          }
          public Connection getCon()
          {
          return con;
          }
          public String getConp()
          {
          return conp;
          }
          public String getDBDriver()
          {
          return DBDriver;
          }
          public String getDBName()
          {
          return DBName;
          }
          public boolean getDebug()
          {
          return xdebug;
          }
          public String getPassword()
          {
          return password;
          }
          public ResultSet getResult()
          {
          return result;
          }
          public String getSql()
          {
          return sql;
          }
          public String getUsername()
          {
          return username;
          }
          public void over()
          throws Throwable
          {
          finalize();
          }
          public ResultSet query()
          throws Exception
          {
          result = null;
          affectedRows = 0;
          if (con == null)
          Connect();
          if (stmt == null)
          stmt = con.createStatement();
          if (sql.substring(0,6).equalsIgnoreCase("select"))

          result = stmt.executeQuery(sql);

          else
          {
          affectedRows = stmt.executeUpdate(sql);
          }
          return result;
          }
          public ResultSet query(String s)
          throws Exception
          {
          sql = s;
          return query();
          }
          public void setDBDriver(String s)
          {
          DBDriver = s;
          }
          public void setDebug(boolean b)
          {
          xdebug = b;
          }
          public void setgetConp(String s)
          {
          conp = s;
          }
          public void setgetDBName(String s)
          {
          DBName = s;
          }
          public void setgetUsername(String s)
          {
          username = s;
          }
          public void setPassword(String s)
          {
          password = s;
          }
          public void setSql(String s)
          {
          sql = s;
          }
          }
          ② DBQueryBean.Java的源代碼如下所示:
          package dbaccess;
          import Java.sql.*;
          import Java.util.*;
          import Java.io.*;
          import Java.lang.reflect.*;

          public class DBQueryBean
          implements Serializable
          {
          DBConnBean dbc;
          String sql = null;
          int rowcount = 0;
          int colcount = 0;
          // int limitcount = 0;
          Vector result = null; 
          public String _WATCH = "";


          public DBQueryBean()
          {
          dbc = new DBConnBean();
          try {
          dbc.Connect();
          } catch(Exception e) {
          handleException(e);
          }
          }
          protected void finalize()
          throws Throwable
          {
          super.finalize();
          if (dbc != null) dbc.over();
          if (result != null) result.removeAllElements();
          }
          public String get(int row, int col)
          {
          if (result==null || row >= result.size()) return null;
          String r[] = (String[])result.elementAt(row);
          if (col >= Java.lang.reflect.Array.getLength(r)) return null;
          return r[col];
          }
          public int getAffRows() { return dbc.getAffectedRows(); }
          public int getColumncount() {
          return colcount;
          }
          public String[] getRow(int row)
          {
          if (result==null || row >= result.size()) return null;
          return (String [])result.elementAt(row);
          /*String ret[] = new String[colcount];
          Vector r = (Vector)result.elementAt(row);
          for (int i=0; i<colcount; i++)
          ret[i] = (String)r.elementAt(i);
          return ret;*/
          }
          public int getRowcount() {
          return rowcount;
          }
          public void handleException(Exception e)
          {
          _WATCH = e.getMessage();
          }
          public void init()
          {
          rowcount = 0;
          colcount = 0;
          // limitcount = 0;
          result = null; 
          }
          public void over()
          throws Throwable
          {
          finalize();
          }
          public int query(String sql)
          {
          result = new Vector();
          int ret = 0;
          try {
          ResultSet rs = dbc.query(sql);
          if (rs == null)
          {
          ret = dbc.getAffectedRows();
          }
          else
          {
          ResultSetMetaData rm = rs.getMetaData();
          colcount = rm.getColumnCount();
          while (rs.next())
          {
          String row[] = new String[colcount];
          for (int i=0; i<colcount; i++)
          row[i] = rs.getString(i+1);
          result.addElement(row);
          rowcount++;
          }
          rs.close(); // to release the resource.
          ret = result.size();
          }
          }
          catch(Exception e)
          {
          handleException(e);
          return -1;
          }

          return ret;
          }
          }

          主站蜘蛛池模板: 武胜县| 海淀区| 凤冈县| 隆昌县| 肃北| 公主岭市| 北安市| 阿拉善右旗| 广灵县| 临洮县| 梅河口市| 平陆县| 华池县| 姜堰市| 肇庆市| 马山县| 泸定县| 永胜县| 班玛县| 清原| 皮山县| 会理县| 化州市| 黎川县| 湖州市| 金平| 且末县| 山阴县| 类乌齐县| 勐海县| 名山县| 九江县| 绍兴县| 湟源县| 井冈山市| 汉中市| 新安县| 正蓝旗| 十堰市| 沧州市| 平潭县|