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類型來做出入參的接收
- 首先我們來定義返回值,入參,及在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”)參數。
- 然後我們來定義mapper.java中的方法:
void getSquenceValue(@Param("map") Map<String, Object> map);
- 再來看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。