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

spring中調用存儲過程

編輯:關於JAVA

springframework.jdbc.object.StoredProcedure是對應存儲過程調用的操作對象,它通過其父類org.springframework.jdbc.object.SqlCall獲得相應的底層API支持(CallableStatementCreator),然後在此基礎之上構建了調用存儲過程的執行方法。

StoredProcedure是抽象類,所以需要實現相應子類以封裝對特定存儲過程的調用,還記得我們在講解JdbcTemplate調用存儲過程時候定義的存儲過程嗎?

CREATE PROCEDURE CountTable(IN tableName varchar(1000),OUT sqlStr varchar(1000) , INOUT v INT)
BEGIN
   set @flag = v;
   set @sql = CONCAT('select count(*) into @res from ' , tableName , ' where ACTIVE_FLAG=?');
   PREPARE stmt FROM @sql;
   EXECUTE stmt using @flag;
   DEALLOCATE PREPARE stmt;
   set v = @res;
   set sqlStr = @sql;
END

通過繼承StoredProcedure,我們可以為該存儲過程的調用提供一個對應的操作對象:

public class CountTableStoredProcedure extends StoredProcedure {

   private static final String PROCEDURE_NAME = "CountTable";

   public static final String IN_PARAMETER_NAME = "tableName";
   public static final String OUT_PARAMETER_NAME = "sqlStr";
   public static final String INOUT_PARAMETER_NAME = "v";

   public CountTableStoredProcedure(DataSource dataSource)
   {
     super(dataSource,PROCEDURE_NAME);
     // setFunction(true);
     declareParameter(new SqlParameter(IN_PARAMETER_NAME,Types.VARCHAR));
     declareParameter(new SqlOutParameter(OUT_PARAMETER_NAME,Types.VARCHAR));
     declareParameter(new SqlInOutParameter(INOUT_PARAMETER_NAME,Types.INTEGER));
     compile();
   }

   public CountTableResult doCountTable(String tableName,Integer v)
   {
     Map paraMap = new HashMap();
     paraMap.put(IN_PARAMETER_NAME, tableName);
     paraMap.put(INOUT_PARAMETER_NAME, v);

     Map resultMap = execute(paraMap);

     CountTableResult result = new CountTableResult();
     result.setSql((String)resultMap.get(OUT_PARAMETER_NAME));
     result.setCount((Integer)resultMap.get(INOUT_PARAMETER_NAME));
     return result;
   }
}

關於該存儲過程操作對象,部分細節我們有必要關注一下:

存儲過程操作對象對應的SQL是存儲過程的名稱,而不是真正意義上的SQL語句,當我們調用compile方法的時候,StoredProcedure的父類SqlCall會根據你提供的存儲過程名稱拼裝真正意義上的符合SQL92標准的存儲過程調用語句,類似於“{ call CountTable(?,?,?) }”的形式。

因為我們的CountTableStoredProcedure只針對CountTable存儲過程調用,所以,該存儲過程的名稱我們在類一開始就聲明為常量:

private static final String PROCEDURE_NAME = "CountTable";如果有多個存儲過程的參數順序相同,結果處理也一樣的話,你也可以將存儲過程的名稱聲明為變量,這完全要取決於具體的應用場景。

在構造方法中,我們將“setFunction(true);”注釋掉了,因為我們調用的CountTable不是一個Function,如果你要調用的存儲過程類型為Function的話,你需要通過該方法將“function”的值設置為true,以告知StoredProcedure在處理調用的時候要區別對待。

在complie之前通過declareParameter聲明參數,這幾乎是雷打不動的慣例,不過,在StoredProcedure中使用declareParameter的時候卻要有所注意了:

針對存儲過程參數類型為IN,OUT和INOUT不同,declareParameter接受的參數類型也應該是SqlParameter,SqlOutParameter和SqlInOutParameter;

SqlParameter,SqlOutParameter和SqlInOutParameter的相應實例在構造的時候,必須指定對應的參數名稱,因為在調用存儲過程的時候,需要根據名稱傳入參數,更需要根據名稱取得調用結果;

StoredProcedure提供了execute方法執行存儲過程調用,通過Map的形式傳入調用所需要的IN或者INOUT類型的參數值,所以,在構建參數Map的時候,該Map中的Key應該與declareParameter時候聲明的參數名稱相同; 另外,execute執行後返回的結果也是Map形式,從該結果Map中取得具體的結果值的時候,也是通過declareParameter中聲明的OUT/INOUT參數名作為key來獲取的,所以,這就是我們將各個參數的名稱在類定義的開始聲明為常量的原因:

public static final String IN_PARAMETER_NAME = "tableName";
public static final String OUT_PARAMETER_NAME = "sqlStr";
public static final String INOUT_PARAMETER_NAME = "v";

無論是輸入參數Map還是輸出參數結果對應的Map,他們中的Key應該與通過declareParameter方法聲明的參數名稱一一對應。

通過擴展StoredProcedure,我們不但封裝了參數的聲明和結果的提取,我們還為調用方提供了強類型的調用方法,現在,調用方可以通過doCountTable方法的強類型參數聲明傳入參數值,並取得強類型的CountTableResult對象作為結果,而不是泛泛的一個Map。

對於存儲過程的調用者來說,它的代碼現在可以簡潔到兩行代碼:

// DataSource dataSource = ...;
CountTableStoredProcedure storedProcedure = new CountTableStoredProcedure(dataSource);
CountTableResult result= storedProcedure.doCountTable("tableName",1);
...

漂亮多了,不是嗎?

StoredProcedure提供了兩個execute方法執行存儲過程的調用,一個就是我們剛才使用的通過Map提供輸入參數的execute方法,另一個則是使用ParameterMapper類型提供輸入參數的execute方法。 那麼,為什麼要提供這個使用ParameterMapper類型提供輸入參數的execute方法那?

ParameterMapper定義的callback方法暴露了相應的Connection,如果說在構造輸入參數列表的時候,必須用到Connection的話,ParameterMapper恰好可以提供支持。比如,Oracle中定義的一存儲過程,接收數組類型作為參數,而在oracle中,你只能通過Oracle.sql.ARRAY和相應的Oracle.sql.ArrayDescriptor來定義數組類型的參數,ARRAY和ArrayDescriptor都需要用到相應的Connection進行構造。所以,對於Oracle中需要使用數組傳入參數的存儲過程來說,我們可以通過如下類似代碼進行調用:

public class OracleStoredProcedure
{
   ...

   public Map call(...)
   {
     ParameterMapper paramMapper = new ParameterMapper(){
       public Map createMap(Connection connection) throws SQLException {
         Map inMap = new HashMap();
         ...
         Integer[] params = new Integer[]{new Integer(1),new Integer(2)};
         ArrayDescriptor desc = new ArrayDescriptor("numbers", connection);
         ARRAY nums = new ARRAY(desc, connection, params);
         inMap.put("ArrayParameterName", nums);
         ...
         return inMap;
       }};

     return execute(paramMapper);
   }
}

當然啦,我們的CountTableStoredProcedure在調用存儲過程的時候也可以使用ParameterMapper傳入相應的調用參數,只不過,ParameterMapper的createMap方法暴露的Connection對於我們來說沒有太大用處罷了。

http://blog.csdn.net/onlyzhangqin/archive/2008/08/08/2787292.aspx

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