存储过程和函数
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
许多关系型数据库管理系统 (RDBMS) 都支持“例程”的概念,通常称之为过程和/或函数。这些概念在编程语言中已经存在了一段时间,也存在于数据库之外。区分过程和函数的著名语言有
- Ada
- BASIC
- Pascal
- 等等...
(存储)过程和(存储)函数之间的通用区别可以总结如下
过程
- 使用 JDBC CallableStatement 调用
- 没有返回值
- 通常支持 OUT 参数
函数
- 可在 SQL 语句中使用
- 有返回值
- 通常不支持 OUT 参数
规则的例外情况
- DB2、H2 和 HSQLDB 在调用函数时不允许使用 JDBC 转义语法。函数必须在 SELECT 语句中使用
- H2 只知道函数(没有 OUT 参数)
- Oracle 函数可能带有 OUT 参数
- Oracle 知道一些出于事务原因不能在 SQL 语句中使用的函数
- Postgres 只知道函数(所有功能合并)。OUT 参数也可以被解释为返回值,这相当优雅/出人意料,取决于您的品味
- Sybase jconn3 JDBC 驱动程序在使用函数上的 JDBC 转义语法时,无法正确处理 null 值
总的来说,可以说,即使 SQL:2008 标准规定得相当好,例程(过程/函数)领域在现代 RDBMS 中也远未标准化。每种数据库都有自己的方式,JDBC 仅在过程/函数实现的多样性上提供了很少的抽象,特别是在涉及游标/UDT/数组等高级数据类型时。
为了稍微简化一下,jOOQ 以相同的方式处理过程和函数,使用更通用的 org.jooq.Routine
类型。
使用 jOOQ 为存储过程和函数进行独立调用
如果您使用 jOOQ 的 代码生成器,它将为您生成 org.jooq.Routine
对象。让我们来看下面的例子
-- Check whether there is an author in AUTHOR by that name and get his ID CREATE OR REPLACE PROCEDURE author_exists (author_name VARCHAR2, result OUT NUMBER, id OUT NUMBER);
生成的工件随后可以这样使用
// Make an explicit call to the generated procedure object: AuthorExists procedure = new AuthorExists(); // All IN and IN OUT parameters generate setters procedure.setAuthorName("Paulo"); procedure.execute(configuration); // All OUT and IN OUT parameters generate getters assertEquals(new BigDecimal("1"), procedure.getResult()); assertEquals(new BigDecimal("2"), procedure.getId();
但您也可以在全局 Routines 类中使用生成的便捷方法来调用该过程
// The generated Routines class contains static methods for every procedure. // Results are also returned in a generated object, holding getters for every OUT or IN OUT parameter. AuthorExists procedure = Routines.authorExists(configuration, "Paulo"); // All OUT and IN OUT parameters generate getters assertEquals(new BigDecimal("1"), procedure.getResult()); assertEquals(new BigDecimal("2"), procedure.getId();
有关过程的 代码生成 的更多详细信息,请参阅手册中关于 过程和代码生成 的部分。
在 SQL 中内联存储函数引用
与过程不同,函数可以内联到 SQL 语句中,以生成 列表达式 或 表表达式,如果您使用 解嵌套运算符。假设您有这样一个函数
-- Check whether there is an author in AUTHOR by that name and get his ID CREATE OR REPLACE FUNCTION author_exists (author_name VARCHAR2) RETURN NUMBER;
生成的工件随后可以这样使用
-- This is the rendered SQL SELECT AUTHOR_EXISTS('Paulo') FROM DUAL
// Use the static-imported method from Routines: boolean exists = create.select(authorExists("Paulo")).fetchOne(0, boolean.class);
有关在 SQL 语句中内联存储函数引用的更多信息,请参阅手册中关于 用户定义函数 的部分。
反馈
您对本页有什么反馈吗? 我们很乐意听取您的意见!