【永恒的瞬間】
          ?Give me hapy ?

          簡(jiǎn)介:JDBC 中的語(yǔ)句處理

          在 JDBC 應(yīng)用程序中,JDBC 語(yǔ)句對(duì)象用于將 SQL 語(yǔ)句發(fā)送到數(shù)據(jù)庫(kù)服務(wù)器。一個(gè)語(yǔ)句對(duì)象與一個(gè)連接相關(guān)聯(lián),應(yīng)用程序與數(shù)據(jù)庫(kù)服務(wù)器之間的通信由語(yǔ)句對(duì)象來(lái)處理。

          JDBC 中有三種類型的語(yǔ)句對(duì)象:

          1. 常規(guī)語(yǔ)句(General statement)
          2. 預(yù)置語(yǔ)句(Prepared statement)
          3. 可調(diào)用語(yǔ)句(Callable statement)

          語(yǔ)句對(duì)象與一個(gè)連接相關(guān)聯(lián),所以要?jiǎng)?chuàng)建一個(gè)語(yǔ)句對(duì)象,首先應(yīng)該建立一個(gè)數(shù)據(jù)庫(kù)連接。

          創(chuàng)建連接

          清單 1 中的代碼示例演示了如何創(chuàng)建連接:


          清單 1.裝載 Informix 驅(qū)動(dòng)程序并創(chuàng)建一個(gè)連接的代碼示例
                      Connection con = null;
                      try {
                      Class.forName("com.informix.jdbc.IfxDriver");
                      String url = "jdbc:informix-sqli://hostname:port_number/dbname:
                      informixserver=servername; userid=userid;password=pwd;";
                      con = DriverManager.getConnection(url);
                      }
                      

          現(xiàn)在逐個(gè)考察這三種類型的語(yǔ)句對(duì)象。






          常規(guī)語(yǔ)句

          可以使用連接的 createStatement 方法創(chuàng)建這種語(yǔ)句。這種語(yǔ)句專用于不需要傳遞任何值作為參數(shù)的 SQL 語(yǔ)句。


          清單 2. 演示創(chuàng)建語(yǔ)句的示例代碼
                      Statement stmt = con.createStatement();
                      cmd = "create database testDB;";
                      rc = stmt.executeUpdate(cmd);
                      stmt.close();
                      






          預(yù)置語(yǔ)句

          預(yù)置語(yǔ)句是 statement 類的一個(gè)子類。預(yù)置語(yǔ)句與 statement 類的主要區(qū)別在于,前者可以只編譯和優(yōu)化一次,然后通過(guò)設(shè)置不同的參數(shù)值多次使用。所以,如果想多次執(zhí)行一條語(yǔ)句,那么預(yù)置語(yǔ)句是更好的選擇。由于已經(jīng)預(yù)先編譯好,所以減少了執(zhí)行時(shí)間。因此,預(yù)置語(yǔ)句的優(yōu)點(diǎn)是,它不僅包含一條 SQL 語(yǔ)句,而且還是一條預(yù)先編譯好的 SQL 語(yǔ)句。另一個(gè)區(qū)別是,SQL 語(yǔ)句在創(chuàng)建后就被提供給預(yù)置語(yǔ)句。


          清單 3. 解釋預(yù)置語(yǔ)句的示例代碼
                      PreparedStatement pstmt = con.prepareStatement("UPDATE tab1 "+
                      "set col1 = ? where key = 1");
                      pstmt.setShort(1, (short)2);
                      int rowcount = pstmt.executeUpdate();
                      

          在此,同一個(gè)預(yù)置語(yǔ)句可用于不同的 col1 值。參數(shù)一旦設(shè)定,它的值將保持不變,直到被重新設(shè)置或者 clearParameters 被調(diào)用。這項(xiàng)特性使得預(yù)置語(yǔ)句可以用于批量處理 INSERT/UPDATE

          批量更新

          通過(guò)設(shè)置多個(gè)值,批量更新特性提高了需要多次執(zhí)行的語(yǔ)句的性能。這樣可以將多個(gè)更新操作提交到一個(gè)數(shù)據(jù)源并進(jìn)行一次性處理。語(yǔ)句對(duì)象也可以使用批量更新。但語(yǔ)句對(duì)象提交不同的 SQL 語(yǔ)句進(jìn)行批處理,而預(yù)置語(yǔ)句提交的是一組參數(shù)。

          清單 4 顯示了如何使用預(yù)置語(yǔ)句進(jìn)行批量插入:


          清單 4. 演示批量更新的示例代碼
                      PreparedStatement pst = conn.prepareStatement("insert into tab1 values (?)");
                      for loop....
                      {
                      pst.setInt (1, i);
                      pst.addBatch();
                      }
                      pst.executeBatch();
                      

          addBatch 方法將語(yǔ)句添加到一個(gè)緩存中,然后使用 executeBatch() 方法轉(zhuǎn)儲(chǔ)到數(shù)據(jù)庫(kù)中。所以它節(jié)省了語(yǔ)句的編譯/優(yōu)化,因?yàn)樗痪幾g一次(對(duì)于預(yù)置語(yǔ)句),而且還節(jié)省了與服務(wù)器之間的往返,因?yàn)樗淮涡园l(fā)送了批量插入。





          可調(diào)用語(yǔ)句

          這是調(diào)用 SQL 語(yǔ)句的第三種方法,它提供了一種從 Java™ 程序中調(diào)用服務(wù)器上的存儲(chǔ)過(guò)程的方式。可調(diào)用語(yǔ)句也需要先作準(zhǔn)備,然后使用 set 方法設(shè)置它們的參數(shù)。可以通過(guò)以下兩種方式設(shè)置參數(shù)值:

          1. 順序位置
          2. 命名參數(shù)

          順序位置是傳統(tǒng)的參數(shù)設(shè)置方式,它根據(jù)參數(shù)在 CallableStatements 中的位置來(lái)設(shè)置參數(shù)。但是,命名參數(shù)則提供了更大的靈活性,它允許根據(jù)名稱而不是順序位置來(lái)設(shè)置參數(shù)。在調(diào)用例程時(shí),必須以名稱或順序格式指定 CallableStatement 的參數(shù)。例如,如果對(duì)一個(gè)參數(shù)使用了參數(shù)名稱,那么對(duì)所有其他參數(shù)也必須使用參數(shù)名稱。

          在調(diào)用具有許多參數(shù),而且其中一些參數(shù)有默認(rèn)值的存儲(chǔ)過(guò)程時(shí),命名參數(shù)特別有用。如果過(guò)程是惟一的,那么可以省略有默認(rèn)值的參數(shù),并且可以按任意順序輸入?yún)?shù)。命名參數(shù)使應(yīng)用程序更加健壯,所以,即使存儲(chǔ)過(guò)程中參數(shù)的順序發(fā)生了改變,也不必修改應(yīng)用程序。

          JDBC 驅(qū)動(dòng)程序提供了 DatabaseMetaData.supportsNamedParameters() 方法來(lái)確認(rèn)驅(qū)動(dòng)程序和 RDMS 是否支持 CallableStatement 中的命名參數(shù)。如果支持命名參數(shù),則系統(tǒng)返回 true。例如:


          清單 5. supportsNamedParameters() 的使用
                      Connection myConn = . . .   // connection to the RDBMS for Database
                      DatabaseMetaData dbmd = myConn.getMetaData();
                      if (dbmd.supportsNamedParameters() == true)
                      {
                      System.out.println("NAMED PARAMETERS FOR CALLABLE"
                      + "STATEMENTS IS SUPPORTED");
                      }
                      

          獲取存儲(chǔ)過(guò)程的參數(shù)名稱

          可以使用 DatabaseMetaDatagetprocedureColumns 獲取存儲(chǔ)過(guò)程的參數(shù)名稱,該方法的定義如清單 6 所示:


          清單 6. getProcedureColumn() 方法的使用
                      Connection myConn = . . .   // connection to the RDBMS for Database
                      . .
                      DatabaseMetaData dbmd = myConn.getMetaData();
                      ResultSet rs = dbmd.getProcedureColumns(
                      "myDB", schemaPattern, procedureNamePattern, columnNamePattern);
                      rs.next() {
                      String parameterName = rs.getString(4);
                      - - - or - - -
                      String parameterName = rs.getString("COLUMN_NAME");
                      - - -
                      System.out.println("Column Name: " + parameterName);
                      

          getProcedureColumns() 方法的參數(shù)相匹配的所有列的名稱都將被顯示。

          清單 7 顯示了 CallableStatements 中的命名參數(shù)的使用。

          創(chuàng)建存儲(chǔ)過(guò)程


          清單 7. 可調(diào)用 OUT 參數(shù)的使用
                      create procedure createProductDef(productname   varchar(64),
                      productdesc  varchar(64),
                      listprice    float,
                      minprice     float,
                      out prod_id      float);
                      . . .
                      let prod_id="value for prod_id";
                      end procedure;
                      

          清單 8 中的 Java 代碼首先創(chuàng)建一個(gè)有 5 個(gè)參數(shù)的 CallableStatement,這 5 個(gè)參數(shù)與存儲(chǔ)過(guò)程中的參數(shù)相對(duì)應(yīng)。JDBC 調(diào)用的括號(hào)中的問(wèn)號(hào)字符 (?) 對(duì)參數(shù)進(jìn)行引用。設(shè)置或注冊(cè)所有的參數(shù)。使用格式 cstmt.setString("arg", name); 命名參數(shù),其中 arg 是相應(yīng)的存儲(chǔ)過(guò)程中的參數(shù)名稱。這里不需要按照存儲(chǔ)過(guò)程中的參數(shù)順序來(lái)命名參數(shù)。


          清單 8. 可調(diào)用命名參數(shù)的使用
                      String sqlCall = "{call CreateProductDef(?,?,?,?,?)}";
                      CallableStatement cstmt = conn.prepareCall(sqlCall);
                      cstmt.setString("productname", name);     // Set Product Name.
                      cstmt.setString("productdesc", desc);     // Set Product Description.
                      cstmt.setFloat("listprice", listprice);   // Set Product ListPrice.
                      cstmt.setFloat("minprice", minprice);     // Set Product MinPrice.
                      // Register out parameter which should return the product is created.
                      cstmt.registerOutParameter("prod_id", Types.FLOAT);
                      // Execute the call.
                      cstmt.execute();
                      // Get the value of the id from the OUT parameter: prod_id
                      float id = cstmt.getFloat("prod_id");
                      

          如果 CallableStatement 中的參數(shù)數(shù)量少于存儲(chǔ)過(guò)程中的參數(shù)數(shù)量,那么剩下的參數(shù)必須有默認(rèn)值。不需要為有默認(rèn)值的參數(shù)設(shè)置值,因?yàn)榉?wù)器會(huì)自動(dòng)使用默認(rèn)值。例如,如果一個(gè)存儲(chǔ)過(guò)程有 10 個(gè)參數(shù),其中 4 個(gè)參數(shù)沒(méi)有默認(rèn)值,6 個(gè)參數(shù)有默認(rèn)值,那么在 CallableStatement 中必須至少有 4 個(gè)問(wèn)號(hào)。也可以使用 5 個(gè)、6 個(gè)或至多 10 個(gè)問(wèn)號(hào)。在下面這個(gè)惟一的存儲(chǔ)過(guò)程中,參數(shù) listpriceminprice 有默認(rèn)值:


          清單 9. 創(chuàng)建包括具有默認(rèn)值的參數(shù)的過(guò)程
                      create procedure createProductDef(productname   varchar(64),
                      productdesc  varchar(64),
                      listprice    float default 100.00,
                      minprice     float default  90.00,
                      out prod_id      float);
                      . . .
                      let prod_id = value for prod_id;
                      end procedure;

          清單 10 中的 Java 代碼使用少于存儲(chǔ)過(guò)程中參數(shù)數(shù)量的參數(shù)(存儲(chǔ)過(guò)程中有 5 個(gè)參數(shù),而代碼中只使用 4 個(gè)參數(shù))調(diào)用存儲(chǔ)過(guò)程。由于 listprice 有一個(gè)默認(rèn)值,因此可以在 CallableStatement 中省略它。


          清單 10. 默認(rèn)參數(shù)的使用
                      String sqlCall = "{call CreateProductDef(?,?,?,?)}";
                      // 4 params for 5 args
                      CallableStatement cstmt = conn.prepareCall(sqlCall);
                      cstmt.setString("productname", name);   // Set Product Name.
                      cstmt.setString("productdesc", desc);   // Set Product Description.
                      cstmt.setFloat("minprice", minprice);   // Set Product MinPrice.
                      // Register out parameter which should return the product id created.
                      cstmt.registerOutParameter("prod_id", Types.FLOAT);
                      // Execute the call.
                      cstmt.execute();
                      // Get the value of the id from the OUT parameter: prod_id
                      float id = cstmt.getFloat("prod_id");
                      

          如果可調(diào)用語(yǔ)句包含 OUTINOUT 參數(shù),那么需要使用 CallableStatement 的 registerOutParameter 注冊(cè)這些參數(shù)。清單 11 使用 out 參數(shù) prod_id 創(chuàng)建一個(gè)具有 OUT 參數(shù)的存儲(chǔ)過(guò)程。類似地,可以使用關(guān)鍵字 INOUT 創(chuàng)建 INOUT 參數(shù)。


          清單 11. INOUT 和 OUT 參數(shù)的使用
                      create procedure createProductDef(productname   varchar(64),
                      productdesc  varchar(64),
                      inout    listprice    float default 100.00,
                      minprice     float default  90.00,
                      out prod_id      float);     

          清單 12 使用 CallableStatements registerOutparameter 方法注冊(cè) CallableStatement 的 out 參數(shù)。


          清單 12. 使用 CallableStatement 注冊(cè) OUT 參數(shù)
                      cstmt.registerOutParameter("prod_id", Types.FLOAT);
                      

          清單 13 將使用命名參數(shù)特性的所有語(yǔ)句合并在一起:


          清單 13. 演示命名參數(shù)功能的程序
                      package Callable;
                      import java.sql.CallableStatement;
                      import java.sql.Connection;
                      import java.sql.DriverManager;
                      import java.sql.ResultSet;
                      import java.sql.SQLException;
                      import java.sql.Statement;
                      import java.sql.Types;
                      public class out1 {
                      static Connection conn;
                      public static void main(String[] args) {
                      getConnect();
                      System.out.println("Connection Established");
                      createProc();
                      runthis();
                      System.out.println("\n=============Finished=============");
                      System.exit(0);
                      }
                      private static void getConnect() {
                      try
                      {
                      Class.forName("com.informix.jdbc.IfxDriver");
                      String url = "jdbc:informix-sqli://host name or ip :porn number/database
                      name:informixserver=dbservername;";
                      System.out.println("URL: "+url);
                      conn = DriverManager.getConnection(url);
                      }
                      catch( Exception e )
                      {
                      e.printStackTrace();
                      System.exit(1);
                      }
                      }
                      private static void createProc() {
                      String str=null;
                      Statement stmt = null;
                      try
                      {
                      stmt = conn.createStatement();
                      }
                      catch (SQLException e2)
                      {
                      e2.printStackTrace();
                      }
                      str="drop function c_out_proc";
                      try
                      {
                      stmt.executeUpdate (str);
                      }
                      catch (SQLException e1)
                      {	}
                      str = "create function  c_out_proc ( i int, OUT d varchar(20) ) \n" +
                      "returning float; \n" +
                      "define f float; \n" +
                      "let d= \"Hello OUT\"; \n" +
                      "let f=i*2; \n" +
                      "return f; \n" +
                      "end function; \n";
                      try
                      {
                      stmt.executeUpdate (str);
                      System.out.println("Function created \n");
                      }
                      catch (SQLException e)
                      {
                      System.out.println("Error on creating function: " + e.toString());
                      System.exit(1);
                      }
                      }
                      private static void runthis()
                      {
                      CallableStatement cstmt = null;
                      String command = "{? = call c_out_proc(?, ?)}  ";
                      try
                      {
                      cstmt = conn.prepareCall (command);
                      cstmt.setInt(1, 2);
                      cstmt.registerOutParameter(2, Types.VARCHAR);
                      ResultSet rs = cstmt.executeQuery();
                      if (rs == null)
                      {
                      System.out.println("rs is null *** this is BAD.");
                      System.exit(0);
                      }
                      else
                      {
                      rs.next();
                      System.out.println(rs.getFloat(1));
                      System.out.println(cstmt.getString(2));
                      }
                      }
                      catch (SQLException e)
                      {
                      e.printStackTrace();
                      }
                      }
                      }


          posted on 2008-05-29 13:45 ???MengChuChen 閱讀(1596) 評(píng)論(0)  編輯  收藏 所屬分類: JAVAEE
          主站蜘蛛池模板: 贵州省| 石河子市| 内乡县| 尉犁县| 尖扎县| 大宁县| 九龙坡区| 荣昌县| 汉寿县| 万荣县| 崇州市| 阜平县| 临沂市| 石狮市| 横山县| 响水县| 珠海市| 安多县| 海晏县| 夹江县| 山西省| 容城县| 景泰县| 吴旗县| 靖安县| 鸡西市| 崇文区| 子洲县| 萝北县| 察隅县| 河间市| 井研县| 舟曲县| 梅州市| 永年县| 珠海市| 玉林市| 手游| 囊谦县| 桦南县| 锦州市|