You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 12:54:18