使用瘦jdbc驱动程序创建oracle db触发器

时间:2010-11-05 14:52:30

标签: java sql oracle triggers ora-00900

目前我正在为应用程序设置测试环境。我在我的测试环境中使用jUnit和Spring。在测试执行之前,我想设置一个数据库测试环境状态。我已经编写了SQL脚本(模式和数据),它们在Oracles SQLDeveloper中运行良好。当我尝试使用oracle thin 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驱动程序创建一个触发器。

干杯!

凯文

3 个答案:

答案 0 :(得分:2)

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

测试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);
    }
}

答案 1 :(得分:1)

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

由于您使用BEGIN ... END;,请确保在发送给数据库的SQL中;之后确实有END

如果不是原因,check this article

答案 2 :(得分:1)

我知道这是一个老帖子,但这是我的答案。

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

在触发器中,触发器内部通常会有分号,因此查询会被严重分割并执行。

解决方案是使用另一个拆分字符(例如“|”),如下所示:

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