Java 1.8+Jooq 3.10.3调用Postgres 10.1表参数函数报错求助
问题分析与解决方案
你遇到的这个报错,核心原因是PostgreSQL的表行类型(testtab类型)和jOOQ生成的TesttabRecord Java对象无法直接自动映射。jOOQ默认不会把TesttabRecord实例转换成PostgreSQL能识别的行类型参数,所以抛出了SQLDialectNotSupportedException。
下面是具体的修复方案和注意事项:
方案1:手动构造行类型参数调用函数
你可以用jOOQ的DSL.row()方法构造符合PostgreSQL行类型要求的参数,替代直接传入TesttabRecord对象。两种实现方式如下:
方式A:结合生成的Testfunc类调用
try (Connection conn = DriverManager.getConnection(url, userName, password)) { DSLContext cxt = DSL.using(conn, SQLDialect.POSTGRES); TesttabRecord r = new TesttabRecord(1, "test"); // 用row()方法构造匹配testtab行类型结构的参数 Row2<Integer, String> rowParam = DSL.row(r.getId(), r.getTxt()); Testfunc f = new Testfunc(); f.setVal(rowParam); // 传入Row对象而非TesttabRecord f.execute(cxt.configuration()); }
方式B:直接用DSL API调用函数(更灵活)
try (Connection conn = DriverManager.getConnection(url, userName, password)) { DSLContext cxt = DSL.using(conn, SQLDialect.POSTGRES); TesttabRecord r = new TesttabRecord(1, "test"); Row2<Integer, String> rowParam = DSL.row(r.getId(), r.getTxt()); // 直接调用PostgreSQL函数 cxt.execute(DSL.select(DSL.function("testfunc", Void.class, rowParam))); }
方案2:通过代码生成器优化类型映射
如果想更优雅地使用表类型参数,可以让jOOQ为PostgreSQL的表行类型生成对应的UDT(用户定义类型)类。需要修改jOOQ生成器配置,开启UDT支持:
生成器配置示例(XML)
<generator> <database> <name>org.jooq.meta.postgres.PostgresDatabase</name> <!-- 开启UDT生成,包含PostgreSQL的表行类型 --> <includeUDTs>true</includeUDTs> <!-- 指定要生成的对象,按需调整 --> <includes>testtab|testfunc</includes> </database> </generator>
重新生成代码后,jOOQ会生成Testtab UDT类,此时可以把TesttabRecord转换为UDT对象传入函数:
try (Connection conn = DriverManager.getConnection(url, userName, password)) { DSLContext cxt = DSL.using(conn, SQLDialect.POSTGRES); TesttabRecord r = new TesttabRecord(1, "test"); // 将Record转换为UDT对象 Testtab udtParam = Testtab.values(r.getId(), r.getTxt()); Testfunc f = new Testfunc(); f.setVal(udtParam); f.execute(cxt.configuration()); }
额外重要修复:PostgreSQL函数逻辑错误
你的函数内部的插入语句存在问题:insert into testtab select * from val中,val是单个行类型变量,不是表,执行时会报"more than one row returned by a subquery used as an expression"错误。需要修改为以下两种写法之一:
-- 写法1:直接引用行类型的字段 CREATE OR REPLACE FUNCTION public.testfunc(val testtab) RETURNS void LANGUAGE 'plpgsql' AS $$ begin insert into testtab(id, txt) values (val.id, val.txt); end; $$;
-- 写法2:用括号包裹行类型,展开所有字段 CREATE OR REPLACE FUNCTION public.testfunc(val testtab) RETURNS void LANGUAGE 'plpgsql' AS $$ begin insert into testtab select (val).*; end; $$;
内容的提问来源于stack exchange,提问作者codemonkey
相关产品推荐
相关产品推荐

