java.sql.SQLSyntaxErrorException: ORA-01729: 使用 Java 存储过程时需要数据库链接名称
Posted
技术标签:
【中文标题】java.sql.SQLSyntaxErrorException: ORA-01729: 使用 Java 存储过程时需要数据库链接名称【英文标题】:java.sql.SQLSyntaxErrorException: ORA-01729: database link name expected while using Java stored procedure 【发布时间】:2019-01-04 10:46:40 【问题描述】:我在 Oracle 中创建了一个 java 存储过程,使用查询:
CREATE OR REPLACE PROCEDURE GETSHEETROWS(I_file_id number, I_sheetNode clob,template_key varchar2 ,wksht_key varchar2 ,wksht_name varchar2 )
AS LANGUAGE JAVA
NAME 'SheetRowsJson.getSheetRows(int, java.sql.Clob, java.lang.String, java.lang.String, java.lang.String)';
/
以下是我的 java 代码。 (输入I_sheetnode
是json类型。由于plsql中没有Jsontype
数据类型,所以我在那里用clob
,所以我这里用同样的)
public static void getSheetRows( int I_file_id, Clob I_sheetNode, String
template_key, String wksht_key,String wksht_name )
try
String url = "jdbc:oracle:thin:@xxxxx:port/yyyyy";
Connection conn = DriverManager.getConnection(url,"username","password");
System.out.println("-------------------Connection Successful--------------------------------");
String sheetRows = "select X.Node,X.rn from json_table (("+ I_sheetNode.toString() +"),'$.table_row[*]' COLUMNS(rn for ordinality,Node varchar2(4000) FORMAT JSON PATH '$')) X";
PreparedStatement ps=conn.prepareStatement(sheetRows);
ResultSet rs = ps.executeQuery();
/* Remaining code goes here */
当我尝试像这样运行程序时,
set serveroutput on;
call dbms_java.set_output(50);
execute GETSHEETROWS(14,'"name":"sheet","table_row":["value":"1","item":"11111","id":"2","value":"1","action":"NEW","value":"2","item":"22222","id":"3","value":"4","action":"NEW"]','TEMPLATE','SHEET','Sheet1');
/
我得到以下输出:
Call completed.
-------------------Connection Successful--------------------------------
java.sql.SQLSyntaxErrorException: ORA-01729: database link name expected
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:450)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:399)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1059)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:522)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:257)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:587)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:225)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:53)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:774)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java)
at SheetRowsJson.getSheetRows(SheetRowsJson.java:25)
PL/SQL procedure successfully completed.
我无法找出原因。既然正在打印“连接成功”,那么连接真的成功了吗?或不?如果不是,为什么?
注意:我已经使用 loadjava
实用程序加载了 java 类。
【问题讨论】:
我们看不到“剩余代码在此处”,当您尝试获取相同的数据或从数据库中调用某些内容时,问题可能就在那里。 您没有向我们展示实际引发错误的代码 - 包括整个 Java 过程,因此我们至少可以看到第 25 行是什么以及您在其中执行的查询。该错误表明您有一个带有流浪@
的查询,可能是由于错误地构造了查询字符串或未正确设置变量,但由于我们看不到您的代码,我们只能做出模糊的猜测。
@AlexPoole 编辑了代码..
@OracleDev 编辑了代码..
【参考方案1】:
如果您为生成的语句添加基本调试打印,例如:
System.out.println(sheetRows);
你会看到类似的东西:
select X.Node,X.rn from json_table ((oracle.sql.CLOB@77556fd),'$.table_row[*]' COLUMNS(rn for ordinality,Node varchar2(4000) FORMAT JSON PATH '$')) X
toString()
方法向您显示对象 ID,而不是字符串内容。并且该 ID 中的 @
导致您看到的错误(因为 77556fd
或您看到的任何值都不是有效的对象标识符)。
您可以嵌入实际传入的字符串值,但您必须将其括在单引号中,并且您会受到数据库中字符串文字大小的限制(4k 或 32k,具体取决于版本)和设置),这首先使使用 CLOB 毫无意义;并且无论如何您都应该使用绑定变量,例如:
sheetRows = "select X.Node,X.rn from json_table (?,'$.table_row[*]' COLUMNS(rn for ordinality,Node varchar2(4000) FORMAT JSON PATH '$')) X";
PreparedStatement ps=conn.prepareStatement(sheetRows);
ps.setClob(1, I_sheetNode);
ResultSet rs= ps.executeQuery();
我收到“java.sql.SQLException: ORA-22922: 不存在的 LOB 值”。
我最初是在数据库之外进行测试,但确实看到这更全面地复制了您的设置。到目前为止,我避免它的唯一方法是避免隐式临时 CLOB:
create table t (c) as (
select to_clob('"name":"sheet","table_row":["value":"1","item":"11111","id":"2","value":"1","action":"NEW","value":"2","item":"22222","id":"3","value":"4","action":"NEW"]') from dual
);
declare
l_clob clob;
begin
select c into l_clob from t;
getsheetrows(14, l_clob, 'TEMPLATE', 'SHEET', 'Sheet1');
end;
/
【讨论】:
很好的解释! :) 但现在我得到一个“java.sql.SQLException:ORA-22922:不存在的 LOB 值”。我曾尝试在通话中使用 to_clob(执行 GETSHEETROWS(14,to_clob('"name":"sheet"........')),但没有运气。 无论如何,您的原始测试调用都会将您的 varchar2 字符串文字隐式转换为 CLOB。该错误是来自 setClob、executeQuery 还是您的测试调用? 它在测试调用期间出现 那似乎是因为它是一个临时的LOB,而且我认为它是由PL/SQL 端发布的,而Java 端仍在尝试使用它,这很尴尬。我只能通过创建具有该值的表然后将其用作调用的一部分来避免它。不完全确定原因,但希望您的真实值无论如何都来自表格。 当然,所有这些都假设您有正当理由首先使用 Java 来执行此操作... *8-)【参考方案2】:连接不成功。
在所有情况下都将打印“连接成功”消息。即使 getConnection 返回 null 或错误,System.out.print 仍然会打印“连接成功”。
您可能想要添加 if 语句或 try catch 语句来检查连接是否存在,而不是添加 System.out.print 语句,该语句不检查连接是否存在,只会打印“连接成功”
PS:检查您的网址和/或您正在使用的罐子。
【讨论】:
我认为这不是真的。如果连接不成功,那么可能会抛出 SQLException,所以它不会到达下一行?另外,抛出的错误来自数据库,因此它必须在执行查询时连接(我们看不到......)以上是关于java.sql.SQLSyntaxErrorException: ORA-01729: 使用 Java 存储过程时需要数据库链接名称的主要内容,如果未能解决你的问题,请参考以下文章