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。