程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用命名參數處理CallableStatement

使用命名參數處理CallableStatement

編輯:關於JAVA

簡介:JDBC中的語句處理

在JDBC應用程序中,JDBC語句對象用於將SQL語句發送到數據庫服務器。一個語句對象與一個連接相關聯,應用程序與數據庫服務器之間的通信由語句對象來處理。

JDBC中有三種類型的語句對象:

常規語句(General statement)

預置語句(Prepared statement)

可調用語句(Callable statement)

語句對象與一個連接相關聯,所以要創建一個語句對象,首先應該建立一個數據庫連接。

創建連接

清單 1中的代碼示例演示了如何創建連接:

清單 1.裝載 Informix驅動程序並創建一個連接的代碼示例

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);
}

現在逐個考察這三種類型的語句對象。

常規語句

可以使用連接的createStatement方法創建這種語句。這種語句專用於不需要傳遞任何值作為參數的SQL語句。

清單 2. 演示創建語句的示例代碼

Statement stmt = con.createStatement();
cmd = "create database testDB;";
rc = stmt.executeUpdate(cmd);
stmt.close();

預置語句

預置語句是 statement 類的一個子類。預置語句與 statement 類的主要區別在於,前者可以只編譯和優化一次,然後通過設置不同的參數值多次使用。所以,如果想多次執行一條語句,那麼預置語句是更好的選擇。由於已經預先編譯好,所以減少了執行時間。因此,預置語句的優點是,它不僅包含一條 SQL語句,而且還是一條預先編譯好的SQL語句。另一個區別是,SQL語句在創建後就被提供給預置語句。

清單 3. 解釋預置語句的示例代碼

PreparedStatement pstmt = con.prepareStatement("UPDATE tab1 "+
"set col1 = ? where key = 1");
pstmt.setShort(1, (short)2);
int rowcount = pstmt.executeUpdate();

在此,同一個預置語句可用於不同的col1 值。參數一旦設定,它的值將保持不變,直到被重新設置或者 clearParameters 被調用。這項特性使得預置語句可以用於批量處理 INSERT/UPDATE。

批量更新

通過設置多個值,批量更新特性提高了需要多次執行的語句的性能。這樣可以將多個更新操作提交到一個數據源並進行一次性處理。語句對象也可以使用批量更新。但語句對象提交不同的SQL語句進行批處理,而預置語句提交的是一組參數。

清單 4 顯示了如何使用預置語句進行批量插入:

清單 4. 演示批量更新的示例代碼

PreparedStatement pst = conn.prepareStatement("insert into tab1 values (?)");
for loop....
{
pst.setInt (1, i);
pst.addBatch();
}
pst.executeBatch();

addBatch方法將語句添加到一個緩存中,然後使用executeBatch()方法轉儲到數據庫中。所以它節省了語句的編譯/優化,因為它只編譯一次(對於預置語句),而且還節省了與服務器之間的往返,因為它一次性發送了批量插入。

可調用語句

這是調用SQL語句的第三種方法,它提供了一種從Java™程序中調用服務器上的存儲過程的方式。可調用語句也需要先作准備,然後使用set方法設置它們的參數。可以通過以下兩種方式設置參數值:

順序位置

命名參數

順序位置是傳統的參數設置方式,它根據參數在CallableStatements中的位置來設置參數。但是,命名參數則提供了更大的靈活性,它允許根據名稱而不是順序位置來設置參數。在調用例程時,必須以名稱或順序格式指定 CallableStatement 的參數。例如,如果對一個參數使用了參數名稱,那麼對所有其他參數也必須使用參數名稱。

在調用具有許多參數,而且其中一些參數有默認值的存儲過程時,命名參數特別有用。如果過程是惟一的,那麼可以省略有默認值的參數,並且可以按任意順序輸入參數。命名參數使應用程序更加健壯,所以,即使存儲過程中參數的順序發生了改變,也不必修改應用程序。

JDBC驅動程序提供了DatabaseMetaData.supportsNamedParameters()方法來確認驅動程序和 RDMS是否支持 CallableStatement中的命名參數。如果支持命名參數,則系統返回 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");
}

獲取存儲過程的參數名稱

可以使用DatabaseMetaData的getprocedureColumns 獲取存儲過程的參數名稱,該方法的定義如清單 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()方法的參數相匹配的所有列的名稱都將被顯示。

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

創建存儲過程

清單 7. 可調用OUT 參數的使用

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 代碼首先創建一個有 5個參數的CallableStatement,這 5個參數與存儲過程中的參數相對應。JDBC 調用的括號中的問號字符 (?) 對參數進行引用。設置或注冊所有的參數。使用格式 cstmt.setString("arg", name); 命名參數,其中arg是相應的存儲過程中的參數名稱。這裡不需要按照存儲過程中的參數順序來命名參數。

清單 8. 可調用命名參數的使用

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中的參數數量少於存儲過程中的參數數量,那麼剩下的參數必須有默認值。不需要為有默認值的參數設置值,因為服務器會自動使用默認值。例如,如果一個存儲過程有 10個參數,其中4個參數沒有默認值,6個參數有默認值,那麼在CallableStatement中必須至少有 4個問號。也可以使用5個、6個或至多10個問號。在下面這個惟一的存儲過程中,參數 listprice和minprice 有默認值:

清單 9. 創建包括具有默認值的參數的過程

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 代碼使用少於存儲過程中參數數量的參數(存儲過程中有 5個參數,而代碼中只使用4個參數)調用存儲過程。由於 listprice 有一個默認值,因此可以在CallableStatement中省略它。

清單 10. 默認參數的使用

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");

如果可調用語句包含 OUT 或 INOUT 參數,那麼需要使用CallableStatement的registerOutParameter 注冊這些參數。清單 11 使用out 參數 prod_id 創建一個具有 OUT 參數的存儲過程。類似地,可以使用關鍵字 INOUT 創建 INOUT 參數。

清單 11. INOUT和OUT 參數的使用

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方法注冊 CallableStatement的out 參數。

清單 12. 使用CallableStatement 注冊 OUT 參數

cstmt.registerOutParameter("prod_id", Types.FLOAT);

清單 13 將使用命名參數特性的所有語句合並在一起:

清單 13. 演示命名參數功能的程序

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();
        }
    }
}

結束語

本文首先介紹了IDS JDBC Driver 提供的各種語句類型。然後描述了命名參數特性,並討論了如何在CallableStatement中使用命名參數。

本文最後列出了一個演示程序,該程序使用了IDS 11 服務器中的命名參數特性。現在,您擁有了嘗試這個特性的工具,並且了解了命名參數特性的優點。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved