【问题标题】:how to write a oracle function to update tables on different schemas如何编写一个 oracle 函数来更新不同模式上的表
【发布时间】:2011-03-30 14:47:37
【问题描述】:

你好 我正在将 wbsphere 应用程序移植到 tomcat,我必须在同一台服务器上处理两个数据库,并且我已经将 tomcat 与 atomikos transactionessential 集成。这是我使用 jta 的第一个项目,oracle dba 告诉我我不需要 xa 和两阶段提交,因为模式位于同一台服务器上。所以我在atomikos 中使用了非xa 方法。 单个架构上的以下代码可以正常工作(按预期提交和回滚):

utx.begin();
conn = //get connection 
if (sAzione.equals("1")) 
sql = "UPDATE parametri set valore =to_char(sysdate,'dd/mm/yyyy HH24:MI:ss') where id_parametri= 9 ";
//execute query
sql = "SELECT SEQ_LOTTO.nextval id FROM dual";
    //other operations
sql = "INSERT INTO LOTTO (id_lotto, numero_lotto, id_area, id_stato_lavorazione, id_autore, id_tipo)";
sql = sql + " VALUES (" + id + ", " + numero + ", " + request.getParameter("idArea") + ",1,"+ session.getAttribute("id_anagrafica")+ "," + request.getParameter("idTipo") + ")";
//execute import and release connection
utx.commit();

在另一个地方,以下 oracle 函数被调用并尝试更改两个模式,它返回代码 1 。我不知道 pl-slq 但在我看来,返回值意味着第一次 delete 出现异常,但第二次 delete 被执行并提交。有人可以解释一下这个功能的含义吗?下面是函数和调用它的代码

    create or replace FUNCTION FN_ELIMINA_RACC (idracc IN NUMBER, idlotto IN NUMBER)
   RETURN NUMBER
IS
   retvalue   NUMBER (1);
BEGIN
   retvalue := 1;

   DELETE FROM npa_collaudo.documento_raccomandata
         WHERE id_raccomandata = idracc;

   retvalue := 2;

   DELETE FROM raccomandata_out
         WHERE id_racc_out = idracc;

   retvalue := 3;

   IF idlotto != 0
   THEN
      UPDATE lotto
         SET numero_racc = numero_racc - 1
       WHERE id_lotto = idlotto;
   END IF;

   retvalue := 0;
   COMMIT;
   RETURN retvalue;
EXCEPTION
   WHEN OTHERS
   THEN
      RETURN retvalue;
END;

//the calling code
    utx.begin();
         //get connection
         sql = "FN_ELIMINA_RACC(" + idRacc + ", " + idLotto + ");";
                ret = connessioneDB.eseguiSP(sql);
         if (!(ret == 0)){
    throw new Exception("exception");
    utx.commit();
//since it returns 1 an exception is raised and rollback gets called

提前感谢您的帮助

编辑:进一步调查这个(糟糕的)代码,多亏了你的回答,我在臭名昭著的“eseguiSP”中找到了这个:

//strSQL is "FN_ELIMINA_RACC(..." 
DBOracle dbType = new DBOracle();
String SQL = "";
int retValue = 0;
SQL = " DECLARE ";
SQL = SQL + " ret NUMBER; ";
SQL = SQL + " BEGIN ";
SQL = SQL + " ret := " + strSQL; 
SQL = SQL + " END; ";
try {
stmt = conn.prepareCall(SQL);
retValue = stmt.executeUpdate(SQL); 
} catch (SQLException e) {
//retValue = false;
}
return retValue;

我已将其更改为:

c = ds.getConnection();
java.sql.CallableStatement cstmt = c.prepareCall("{?=call FN_ELIMINA_RACC(?,?)}");
cstmt.registerOutParameter(1,java.sql.Types.INTEGER);
cstmt.setInt(2, idRacc);
cstmt.setInt(3, idLotto);
cstmt.execute();
ret = cstmt.getInt(1);

现在它工作正常(或至少返回 0)。为什么旧代码即使从 raccomandata_out 中删除记录也总是返回 1?

【问题讨论】:

    标签: java oracle plsql atomikos


    【解决方案1】:

    由于函数返回 1,这表明第一次删除正在引发异常。这会导致控制被切换到EXCEPTION 块,它只是返回。第一次删除后的任何其他代码都不应执行。

    异常处理程序很可怕,因为它会捕获任何异常,将其丢弃,并返回一个标志值,该值很少告诉您发生了什么。它只比WHEN OTHERS THEN NULL; 稍微好一点。写到这里,你无法知道发生了什么异常。应该删除异常处理程序(以便调用代码可以以某种方式捕获和处理异常),或者重写以至少以某种方式记录实际的异常消息 (SQLERRM)。

    最明显的猜测是引发异常是因为执行代码的架构没有对另一个架构中的表的删除访问权限。一个可能相关的 Oracle 怪癖是存储的 PL/SQL 代码(例如此函数)无法利用通过角色授予的访问权限。对其他架构对象的任何访问都必须直接授予用户。

    【讨论】:

    • 我将删除异常处理程序(这是一个很长的路,因为我必须向 dba 提出正式请求)。但是我已经检查了授权,并且 npa_collaudo 所有者已授予其他数据库所有者所有权限。更让我失望的是,下面的 delete 被执行并提交了。可能是因为我配置为非 xa 数据源的 atomikos 数据源?
    【解决方案2】:

    此过程中的异常处理程序并不是特别有用。它完全隐藏了 Oracle 抛出的错误消息。如果完全消除异常处理程序,错误堆栈是什么?

    我的猜测是该过程的所有者没有权限从npa_collaudo.documento_raccomandata 表中删除行。但是如果不知道实际引发了什么异常,就不可能知道这一点。

    【讨论】:

      【解决方案3】:

      你怎么知道函数返回 1?您抛出的异常没有报告 ret 值。调用本身可能会中断 - 尝试从 sql 字符串中删除尾随的 ;。尽管如果是这种情况,您应该从eseguiSP(sql) 获得一个更有用的异常,但它可能隐藏在您的代码中的其他地方(也许更进一步的事情是添加一些使它看起来像返回 1 的东西?);并且两个删除都不应该生效,除非它试图将其视为两个命令并且只有在看到第二个为空时才抱怨。这听起来不太可能,但你永远不会知道,所以无论如何我都会尝试删除分号。

      此外,您可能应该在调用中使用绑定参数,而不是在 sql 中嵌入值。

      您还说过将在异常时调用回滚,并且您有 utx.commit(),但这对于函数中的提交也是多余的。

      【讨论】:

      • 谢谢你的帖子,你让我注意到了一些事情(见编辑)。我猜它在哪里返回ig 1,因为调用executeUpdate(删除1条记录)。
      • 哇。从函数返回的ret 值被忽略,因为匿名块对它不做任何事情。 retValue=1 可能来自 executeUpdate() 返回受影响的行数,但不确定它是否如何处理三个(如果是 idLotto != 0)DML 语句 - 并不是真的为此设计的。如果idLotto 非零但无效,或者没有可删除的内容且idLotto 为零,则它可能会返回零。不过,解释了为什么它需要分号......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多