Oracle Java存储过程编译报#为非法字符问题咨询
问题解答
1. #sql语法的含义
- 该语法不属于标准Java,也不是Oracle Java存储过程的原生特有语法,它是SQLJ静态嵌入式SQL的标准写法。
- SQLJ是早期Java生态推出的数据库开发规范,允许开发者直接在Java代码中用
#sql { SQL语句 }的格式嵌入SQL,通过:变量名的形式直接绑定Java上下文的局部变量作为SQL参数,不需要手写JDBC的样板代码。 - 这类代码不能直接交给标准Java编译器编译,必须先经过SQLJ预处理器转换,把
#sql块翻译成标准JDBC调用的Java代码后,才能正常编译。SQLJ这套方案现在基本已经被淘汰,新版Oracle默认不再预装相关组件。你提到旧实例能正常运行,是因为当时的部署流程先走了SQLJ预编译步骤,不是直接把这段带#sql的源码作为普通Java源文件加载编译的。
2. 成功编译该存储过程的方法
最简便、不需要依赖额外SQLJ组件的方案是直接把#sql嵌入式SQL改写为标准JDBC代码,改写后的源码可以直接通过create or replace and compile java source命令在19c环境编译通过,执行逻辑和原代码完全一致。
改写后的完整Java源码:
create or replace and compile java source named fill_share_content as import java.io.*; import java.sql.*; public class Fill_Share_Content { public static void execute(String directory) throws SQLException { File path = new File( directory ); String[] list = path.list(); String separator = path.separator; // 获取当前数据库会话内置的默认JDBC连接 Connection conn = DriverManager.getConnection("jdbc:default:connection"); for(int i = 0; i < list.length; i++) { String filename = list[i]; File datei = new File( directory + separator + filename ); if ( datei.isFile() ) { Timestamp filedate = new Timestamp( datei.lastModified() ); // 替换原#sql块为标准JDBC逻辑 try (PreparedStatement pstmt = conn.prepareStatement("insert into Share_Content (filename, filedate) values (?, ?)")) { pstmt.setString(1, filename); pstmt.setTimestamp(2, filedate); pstmt.executeUpdate(); } } } conn.close(); } }; /
补充说明:
- 如果你坚持要用原始SQLJ语法,需要先在本地安装Oracle SQLJ预编译器,把源码预编译为标准Java代码后再加载到数据库,但19c版本默认不带SQLJ组件,手动配置的成本远高于直接改写为JDBC代码。
- 如果编译通过后执行时提示文件系统访问权限错误,需要给数据库用户授予对应目录的Java文件读权限,这是Oracle Java存储过程的默认安全限制,和代码本身无关。
内容的提问来源于stack exchange,提问作者simon
相关产品推荐
相关产品推荐

