mybtais調用{? = call procName(?,?) }存儲過程


工作中要將ssh項目中的功能改造成springboot項目接口,遇到了調用存儲過程的問題,進行一下記錄

存儲過程示例

一個簡單的oracle獲取序列值的存儲過程

CREATE OR REPLACE FUNCTION FC_seq_result(p_seqname IN VARCHAR2,
                                         p_type    IN NUMBER) RETURN NUMBER IS
  v_seq    VARCHAR2(1024);
  v_pro    VARCHAR2(1024);
  v_result NUMBER(10);
BEGIN
  IF p_type = 1 THEN
    v_pro := '.NEXTVAL';
  ELSIF p_type = 0 THEN
    v_pro := '.CURRVAL';
  END IF;
  v_seq := 'SELECT ' || p_seqname || v_pro || ' FROM DUAL';
  EXECUTE IMMEDIATE V_SEQ
    INTO V_RESULT;
  Return(v_result);
END;

ssh實現代碼:

/***
	 * 獲取Seq值,type爲1獲取nextval;type爲0獲取currval
	 * 
	 * @param sqNm
	 * @param type
	 * @return
	 * @throws Exception
	 */
	public String getSquenceValue(String sqNm, int type) throws Exception {
		Connection conn = null;
		CallableStatement pstmt= null;
		ResultSet rs = null;
		try {
			conn = SessionFactoryUtils.getDataSource(getSessionFactory()).getConnection();
			pstmt = conn.prepareCall("{? = call FC_seq_result(?, ?)}");
			pstmt.setString(2, sqNm);
			pstmt.setInt(3, type);
			pstmt.registerOutParameter(1, Types.NUMERIC);
			if ("sqlserver".equals(getDbType())) {
				rs = pstmt.executeQuery();
				while (rs.next()) {
					return rs.getString(1);
				}
				throw new Exception("獲取Sequence失敗,[" + sqNm + "]");
			} else {
				pstmt.executeUpdate();
				Object obj = pstmt.getObject(1);
				if (null != obj && !"".equals(obj.toString())) {
					String seqVal = obj.toString();
					return seqVal;
				}
			}
		} catch (Exception e) {
			throw new Exception("獲取Sequence失敗,[" + sqNm + "]");
		} finally {
			if (null != rs) rs.close();
			if (null != pstmt) pstmt.close();
			if (null != conn) conn.close();
		}
		throw new Exception("獲取Sequence失敗,[" + sqNm + "]");
	}

通過上邊的代碼我們可以看到:
代碼中通過 { ? = call procName(?,?) } 這種方式調用的存儲過程,第一個 是返回值結果。這種方式感覺比較特別,試了幾種方式,終於成功了。

使用mybatis來實現這種方式的存儲過程的調用

使用Map類型來做出入參的接收

  1. 首先我們來定義返回值,入參,及在mapper.xml中調用的寫法,示例:
  <select id="getSquenceValue" parameterType="java.util.Map" statementType="CALLABLE">
		{ #{map.seqNo,mode=OUT, jdbcType=NUMERIC} = call FC_seq_result(#{map.seqName,mode=IN, jdbcType=VARCHAR}, #{map.type,mode=IN, jdbcType=INTEGER})}
  </select>

我們使用 mode=OUT 來定義返回值,mode=IN 來定義入參,jdbcType 來定義類型,statementType="CALLABLE"來聲明調用的是存儲過程。
其中,map是我mapper.java定義的@Param(“map”)參數。

  1. 然後我們來定義mapper.java中的方法:
void getSquenceValue(@Param("map") Map<String, Object> map);
  1. 再來看service如何調用mapper.java的方法
    /**
     * mybatis調用存儲過程,根據序列名獲取序列值
     * @param seqName
     * @param type
     * @return
     */
    private String getSquenceValue(String seqName,Integer type) {
    Map<String, Object> paramMap = new HashMap<String, Object>(4);
    paramMap.put("seqNo",new BigDecimal("0"));
    paramMap.put("seqName",seqName);
    paramMap.put("type",type);
    mapper.getSquenceValue(paramMap);
    return paramMap.get("seqNo").toString();
  }

這樣就實現 ?=call procName(?,?) 這種存儲過程的返回值的獲取。

參考文章:

https://blog.csdn.net/cs373616511/article/details/82890306

注意事項[上邊參考文章也有提到]:

1、 存儲過程的參數和名稱無關,只和順序有關係
2、 存儲過程的output參數,只能通過傳入的map獲取
3、 存儲過程返回的結果集可直接用返回的map接收
4、 存儲過程的return結果需要使用?=call procName(?,?)的第一個參數接收,需要指定對應的mode爲OUT類型
5、 存儲過程對應的數據類型爲枚舉類型,需要使用大寫,如VARCHAR
output是在存儲過程中的參數的返回值(輸出參數),而ReturnValue是存儲過程返回的值(使用return關鍵字),一個存儲過程可以有任意多個依靠參數返回的值,但只有一個ReturnValue。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章