存储过程和存储函数的输入输出
定义一个方法,首先要定义的就是方法名以及入参出参。MySQL中有procedure(存储过程)和function(存储函数)两种类型的SQL语句集合
在Navicat中新建一个Function,Navicat会自动填一个模板
CREATE DEFINER = CURRENT_USER PROCEDURE `NewProc`( )
BEGIN
#Routine body goes here...
END;
这里DEFINER = CURRENT_USER是创建人,
后面PROCEDURE是存储过程,如果是函数的话就是FUNCTION
NewProc是存储过程名称,替换成自定义的名字
再往后的括号里面是参数。BEGIN, END之间就是写代码主体的部分了
本系列主要集中于使用实践,不详述完整的参数列表,CREATE的详细参数请参阅官方文档!
本篇主要介绍存储过程和存储函数参数部分的区别
1.存储函数
考虑一个计算两个数和的函数
CREATE FUNCTION `simple_add_function`(a int, b int) RETURNS int(11)
BEGIN
return a + b;
END
声明函数名为simple_add_function, 入参有两个,分别是a, b, 都是int类型的,该函数返回一个int类型的数字。
函数体里面return了a + b
可以看出,存储函数跟我们在其他编程语言里面用的函数没什么两样,就作为函数来理解就好了。
如果想在Navicat里面显式的调用一个函数
select simple_add_function(1,2);
由于函数里面不能select,因此如果想拿到结果的话,需要自己在外面写个select。
或者赋值给一个变量再select出来
set @temp = simple_add_function(1,2);
select @temp;
为什么这里的变量是@开头的,会在下一节解释
2.存储过程
相对于函数,存储过程的输入输出就丰富了一些,有两进三出
CREATE DEFINER=`cloudpenseuser`@`%` PROCEDURE `simple_add_procedure`(in a int, in b int, inout c int, out total int, out average int)
BEGIN
set total = a + b;
set average = total / 2;
if c > 0 then
select 'ok';
else
select 'error';
set c = 10;
end if;
END
储存过程的参数有in, inout, out三种类型,in, out分别是输入输出很容易理解,inout的参数既可以当输入,也可以当输出,而且在过程内部也可以select来取出数据
可以直接在Navicat或命令行中调用
call simple_add_procedure(4, 2, 0, @a, @b);
考虑上面存储函数对应的Java实体类如下
public class SimpleAddEntity {
int a;
int b;
int c;
int total;
int average;
//此处省略对应的getter和setter
}
使用Mybatis的xml这么写
<select id="simpleAdd" resultType="String">
call simple_add_procedure(#{a}, #{b}, #{c,mode=INOUT, jdbcType=INTEGER}, #{total, mode=OUT, jdbcType=INTEGER, #{average, mode=OUT, jdbcType=INTEGER}})
</select>
对应的Mybatis的interface
public String simpleAdd(SimpleAddEntity simpleAddEntity);
通过mybatis来调用存储过程的时候,resultType是对应存储过程中select的内容,而存储过程out参数输出的内容会自动调用entity中的setter方法更新到对象中,或者用变量进行承接
上述示例的调用方法
SimpleAddEntity simpleAddEntity = new SimpleAddEntity();
simpleAddEntity.setA(4);
simpleAddEntity.setB(2);
String result = mapper.simpleAdd(simpleAddEntity)
System.out.println(simpleAddEntity.getC()); //10
System.out.println(simpleAddEntity.getTotal()); //6
System.out.println(simpleAddEntity.getAverage()); //3
System.out.println(result); //"error"
存储过程具有多种输出方式,开发中可以制定规范,统一使用某种输出方式。
例如可以使用out参数来传递状态和错误信息,通过select取返回数据
需要注意的是Mybatis只能取到第一个select的结果
相互调用
存储过程和函数可以互相调用,按逻辑上的输入输出即可
#获取函数的返回
declare ret varchar(255);
CREATE FUNCTION `function_A`(p_input int) RETURNS varchar(255) #function的声明,这里只是表示了一下,不能正常运行的
set ret = function_A(1); #在function_A中return
select ret;
#获取存储过程的返回
declare outparam varchar(255);
CREATE PROCEDURE `procedure_A`(in input int, out output varchar(255));
call procedure_A(input, outparam); #outparam是procedure_A的out或者inout参数
select outparam; #这里outparam就被赋值了
需要注意的是在存储过程select出来的结果不能由调用它的存储过程获取,会直接输出到最终结果的select
Tips: NodeJS如何取到out参数的返回值
笔者用过nodejs的MySQL包 github.com/mysqljs/mys…
使用的时候results只取select的结果的,这就导致了out返回的参数是没有体现在results中的,可以这么写
connection.query(
'set @x=""; set @y=""; set @z=""; call simple_add_procedure(?, ?, @x, @y, @z); select @x; select@y; select@z',
[4, 2],
function (error, results, fields) {
if (error) throw error
let c = results[results.length - 3][0]['@x']
let total = results[results.length - 2][0]['@y']
let average = results[results.length - 1][0]['@z']
});
写起来比较丑,如果你知道更好的写法,也希望你能教我