【问题标题】:Create a oracle db trigger using thin jdbc driver使用瘦 jdbc 驱动程序创建 oracle db 触发器
【发布时间】:2011-05-05 15:44:11
【问题描述】:

目前我正在为应用程序设置测试环境。我在我的测试环境中使用 jUnit 和 Spring。在测试执行之前,我想设置一个数据库测试环境状态。我已经编写了 SQL 脚本(模式和数据),它们在 Oracle SQLDeveloper 中运行良好。当我尝试使用 oracle 瘦 jdbc 驱动程序执行它们时,执行失败。看起来瘦驱动程序不喜欢创建触发器语句。

我读到我必须使用 oci 驱动程序而不是瘦驱动程序。 oci 驱动程序的问题在于它不是独立于平台的,并且需要时间来设置它。

我的代码示例:

CREATE TABLE "USER"
  (
    USER_ID          NUMBER(10) NOT NULL,
    CREATOR_USER_FK  NUMBER(10) NOT NULL,
    ...
    PRIMARY KEY (USER_ID)
  );
CREATE SEQUENCE SEQ_USER START WITH 1 INCREMENT BY 1;
CREATE TRIGGER "USER_ID_SEQ_INC" BEFORE
  INSERT ON "USER" FOR EACH ROW BEGIN
  SELECT SEQ_USER.nextval
  INTO :new.USER_ID
  FROM DUAL;
END;

如果我执行触发器语句,则执行失败,但我看起来查询的第一部分 (CREATE TRIGGER "USER_ID_SEQ_INC" ... "USER" ... BEGIN ... FROM DUAL;) 已执行成功,但如果我尝试使用它,触发器似乎已损坏。执行失败错误来自语句 END 的第二部分; “ORA-00900: 无效的 SQL 语句”。

有人知道这个问题的解决方案吗?我只想用独立于平台的瘦 jdbc 驱动程序创建一个触发器。

干杯!

凯文

【问题讨论】:

    标签: java sql oracle triggers ora-00900


    【解决方案1】:

    谢谢大家的回答,现在可以正常使用了。原因是语法错误或使用 Spring Framefork 对我的 SQL 代码文件的解释。当我使用 jdbc 的 execute 方法直接执行语句时,它可以工作,当我使用 Spring 功能执行脚本时,执行失败。使用 oracle sql 代码似乎很棘手,因为如果我使用 hsqldb sql 代码它可以正常工作。

    test-condext.xml:

    ...
    <jdbc:initialize-database data-source="dataSource"
        ignore-failures="DROPS" enabled="${jdbc.enableSqlScripts}">
        <jdbc:script location="${jdbc.initLocation}" />
        <jdbc:script location="${jdbc.dataLocation}" />
    </jdbc:initialize-database>
    ...
    

    schema.sql:

    DROP SEQUENCE SEQ_USER;
    DROP TABLE "USER" CASCADE CONSTRAINTS;
    PURGE TABLE "USER";
    CREATE TABLE "USER"
      (
        USER_ID          NUMBER(10) NOT NULL,
        CREATOR_USER_FK  NUMBER(10) NOT NULL,
        PRIMARY KEY (USER_ID)
      );
    ALTER TABLE "USER" ADD CONSTRAINT FK_USER_CUSER FOREIGN KEY (CREATOR_USER_FK) REFERENCES "USER" (USER_ID);
    CREATE SEQUENCE SEQ_USER START WITH 1 INCREMENT BY 1;
    CREATE TRIGGER "USER_ID_SEQ_INC" BEFORE
      INSERT ON "USER" FOR EACH ROW
      WHEN (new.USER_ID IS NULL)
    BEGIN
      SELECT SEQ_USER.nextval
      INTO :new.USER_ID
      FROM DUAL;
    END;
    /
    ALTER TRIGGER "USER_ID_SEQ_INC" ENABLE;

    这很好用!在语句末尾删除; 很重要,触发器语句除外!!!

    @Before
    public void executeSomeSql() {
        Connection c;
        try {
            c = dataSource.getConnection();
            c.createStatement()
                    .execute("CREATE TABLE \"USER\" (USER_ID NUMBER(10) NOT NULL, CREATOR_USER_FK NUMBER(10) NOT NULL, PRIMARY KEY (USER_ID))");
            c.createStatement()
                    .execute("CREATE SEQUENCE SEQ_USER START WITH 1 INCREMENT BY 1");
            c.createStatement()
                    .execute("CREATE OR REPLACE TRIGGER \"USER_ID_SEQ_INC\" BEFORE INSERT ON \"USER\" FOR EACH ROW WHEN (new.USER_ID IS NULL) BEGIN SELECT SEQ_USER.nextval INTO :new.USER_ID FROM DUAL; END;");
        } catch (SQLException e) {
            logger.debug(e);
        }
    }
    

    【讨论】:

      【解决方案2】:

      创建触发器适用于任何类型的 JDBC 驱动程序; SQL 语法一定有问题——这很奇怪,因为 Oracle 应该在您运行 CREATE TRIGGER 时报告(而不是在您第一次使用它时)。

      既然您使用了BEGIN ... END;,请确保您在发送到数据库的 SQL 中的END 之后确实有一个;

      如果这不是原因,check this article

      【讨论】:

      • 感谢 Aaron 的回答和文章。不幸的是,它不是语句中的分号:(
      【解决方案3】:

      我知道这是一篇旧帖子,但这是我的答案。

      默认情况下,Spring“initialize-database”指令使用分号字符:“;”分割指定的脚本。

      在触发器中,触发器内部通常有一个分号,因此查询被严重拆分和执行。

      解决方案是像这样使用另一个拆分字符(例如“|”):

      <jdbc:initialize-database>
          <jdbc:script location="classpath:myscript.sql" separator="|"/>
      </jdbc:initialize-database>
      

      【讨论】:

        猜你喜欢
        • 2019-08-17
        • 1970-01-01
        • 2010-11-05
        • 2011-10-07
        • 1970-01-01
        • 2010-11-07
        • 2013-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多