如何在Spring Boot中通过Oracle存储过程实现分页查询_利用REF CURSOR传递指针

千辰吖_5761

千辰吖_5761

2026-05-21

1061人浏览

原创

Oracle存储过程必须用OUT SYS_REF CURSOR返回结果集,不可直接SELECT或RETURN;JDBC需注册Types.OTHER,MyBatis须用XML+CALLABLE+resultMap,且注意事务与连接释放。

Oracle存储过程必须用REF CURSOR返回结果集

oracle不支持直接在存储过程中用select语句返回行集,必须声明out类型的ref cursor参数,由调用方打开并读取。常见错误是写成return sys_refcursor或试图在过程体里return cursor_var——这在pl/sql中语法非法。

正确写法示例:

CREATE OR REPLACE PROCEDURE P_FENYE(
    p_page_no    IN  NUMBER,
    p_page_size  IN  NUMBER,
    p_result     OUT SYS_REFCURSOR
) AS
    v_offset NUMBER := (p_page_no - 1) * p_page_size;
BEGIN
    OPEN p_result FOR
        SELECT * FROM (
            SELECT a.*, ROWNUM rnum FROM (
                SELECT id, name, create_time FROM player ORDER BY id
            ) a WHERE ROWNUM  v_offset;
END;
  • p_result必须是OUT SYS_REFCURSOR,不能是IN OUT或IN
  • 不要在过程里执行FETCH或CLOSE,那是JDBC或MyBatis的事
  • 如果用ROW_NUMBER() OVER替代嵌套ROWNUM,注意Oracle 12c+才完全支持OFFSET ... FETCH,老版本仍需嵌套写法

Spring Boot里用JdbcTemplate调用带REF CURSOR的存储过程

JdbcTemplate对REF CURSOR有原生支持,但必须用SqlOutParameter显式注册类型为Types.OTHER,否则会报ORA-06550: PLS-00306参数类型不匹配。

关键代码片段:

@Autowired
private JdbcTemplate jdbcTemplate;
<p>public List<map object>> callFenYe(int page, int size) {
String sql = "{call P_FENYE(?, ?, ?)}";
Map<string object> result = new JdbcCall(jdbcTemplate)
.withProcedureName("P_FENYE")
.declareParameters(
new SqlParameter("p_page_no", Types.NUMERIC),
new SqlParameter("p_page_size", Types.NUMERIC),
new SqlOutParameter("p_result", Types.OTHER) // 必须是Types.OTHER
)
.execute(Map.of("p_page_no", page, "p_page_size", size));</string></map></p><pre class="brush:php;toolbar:false;">return (List<map object>>) result.get("p_result");</map>

}

QuantOracle
QuantOracle

63个确定性量化金融计算器 + 10个通过MCP的复合工作流。期权定价、Greeks、奇异衍生品、风险指标、投资组合优化……

下载
  • 别用queryForObject或query直接调用{call ...},它们不处理游标输出
  • SqlOutParameter的name必须和存储过程中OUT参数名完全一致(大小写敏感)
  • 返回的List里字段名默认全大写,因Oracle元数据返回的是大写列名

MyBatis Plus不支持REF CURSOR,改用Mapper XML手动定义

MyBatisPlusInterceptor的PaginationInnerInterceptor只拦截SELECT语句,对存储过程调用无感知;@Select("CALL ...")也不能解析游标。必须退回到XML Mapper方式,并在中用statementType="CALLABLE"。

Mapper XML示例(PlayerMapper.xml):

<select id="selectByProcedure" statementtype="CALLABLE" resulttype="Player">
    {CALL P_FENYE(
        #{pageNo,jdbcType=NUMERIC},
        #{pageSize,jdbcType=NUMERIC},
        #{result,mode=OUT,jdbcType=OTHER,javaType=java.sql.ResultSet,resultMap=playerResultMap}
    )}
</select>
  • resultMap必须提前定义好,不能靠自动映射,因为游标返回的列结构不固定
  • #{result,...}里的mode=OUT和jdbcType=OTHER缺一不可
  • Java接口方法不能用@Select注解,必须配XML,且方法返回值要是List而非Page——分页逻辑已由存储过程完成

容易被忽略的事务与连接泄漏风险

存储过程内部若含DML操作(如分页同时更新统计表),而调用方未开启事务,会导致一致性破坏;更隐蔽的是,REF CURSOR底层依赖数据库连接,若JDBC未正确关闭ResultSet,连接池可能耗尽。

  • 确保调用方方法加@Transactional,尤其当存储过程内有UPDATE/INSERT
  • 用JdbcTemplate时,它会自动关闭游标;但若手写Connection + CallableStatement,必须在finally块中rs.close(); stmt.close(); conn.close();
  • MyBatis里若XML中漏写resultMap,异常堆栈可能只报NullPointerException,实际是ResultSet未被映射就释放了

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

3669

3

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

2023.07.25

2448

9

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

2023.08.02

1400

5

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.09

1338

4

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

2023.09.05

1436

5

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2023.09.20

2378

7

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

2023.09.20

3940

8

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

2023.09.22

18655

6

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程