目录
创建存储过程:
在Oracle中创建一个有输入参数、输出参数、并且输出参数为系统游标的存储过程。
-- 传入开始的页面、结束页面,输出游标为分页查询的employee数据
create or replace procedure getEmpByPage(v_beginPage in int,v_endPage in int,c_emp out sys_refcursor)
as
begin
open c_emp for
select
*
from (
select rownum as rid,emp.* from employees emp
)where rid between (v_beginPage) and (v_endPage);
end;
在Oracle中调用:
首先声明的变量v_emp为employees表的行类型。
但是 存储过程中查询的数据额外增加了一个rownum行号,所以调用的时候会出现“类型不匹配”的错误。
可以将存储过程中查询的*替换为具体的字段,匹配employee表的字段类型。
declare
v_emp employees%rowtype;
c_emp sys_refcursor;
begin
getempbypage(1,5,c_emp);
loop
fetch c_emp into v_emp;
exit when c_emp%notfound;
dbms_output.put_line(v_emp.employee_id||','||v_emp.first_name||','||v_emp.email);
end loop;
close c_emp;
end;
MyBatis中调用
创建参数对象
包含存储过程中的输入、输出参数及其游标的返回类型:
public class OraclePage {
private Integer beginPage;
private Integer endPage;
private List<Employee> emps;
//getter、setter
}
Mapper接口方法
public void getEmpByProcedure(OraclePage page);
Mapper的SQL调用
<select id="getEmpByProcedure" statementType="CALLABLE" useCache="false">
{
call getempbypage(
#{beginPage,mode=IN,jdbcType=INTEGER},
#{endPage,mode=IN,jdbcType=INTEGER},
#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
)
}
</select>
<resultMap type="com.starfall.mybaits.entity.Employee" id="PageEmp">
<id column="employee_id" property="employeeId"/>
<result column="first_name" property="firstName"/>
<result column="last_name" property="lastName"/>
</resultMap>
1、select标签中的statementType属性指定为"CALLABLE" ,useCache使用缓存最好设置为false。(测试发现存储过程不支持二级缓存)
2、存储过程的参数需要指定mode属性,值为IN、OUT、INOUT。同时需要指定jdbcType的枚举类型,Oracle的游标为CURSOR
3、对于返回参数的游标类型。需要指定javaType=ResultSet,并且指定resultMap=PageEmp接收返回的数据。
测试调用
@Test
public void testProcedure() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
OraclePage page = new OraclePage();
page.setBeginPage(1);
page.setEndPage(5);
mapper.getEmpByProcedure(page);
List<Employee> list = page.getEmps();
for (Employee employee : list) {
System.out.println(employee);
}
} finally {
session.close();
}
}
传入创建的OraclePage对象,存储过程查出的数据会根据属性set到对象中。
测试发现,Mybatis调用存储过程需要将输入输出参数包装成一个整体的对象,在传入查询的接口中,如果接口为下方类似的写法:
public void getEmpByProcedure(@Param("beginPage") int beginPage, @Param("endPage") int endPage,
@Param("emps") List<Employee> emps);
反而获取不到查出的数据:List<Employee> emps总是为空。
具体原因有待进一步探究。。。