如何编写oracle函数来更新不同模式的表

你好 我正在将一个应用程序移植到tomcat,我必须在同一台服务器上运行两个数据库,并且我已经将tomcat与atomikos transactionessential集成在一起。这是我与jta的第一个项目,oracle dba告诉我我不需要xa和两阶段提交,因为模式在同一台服务器上。所以我使用了非xa方法与atomikos。 单个模式上的以下代码工作正常(按预期提交和回滚):
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,但在我看来,返回值意味着第一次删除时出现异常,但第二次删除被执行并提交。有人可以解释一下这个功能的含义吗?下面是函数和调用它的代码
    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)。为什么旧的代码总是返回1,即使它从raccomandata_out删除了记录?     
已邀请:
你怎么知道函数返回1?您抛出的例外情况并未报告
ret
值。呼叫本身可能会被破坏 - 尝试从
sql
字符串中删除尾随的
;
。虽然你应该从
eseguiSP(sql)
获得一个更有用的例外,如果是这样的话,但它可能隐藏在你的代码的其他地方(也许更进一步的是添加一些让它看起来像是1的东西?);并且删除都不会生效,除非它试图将其视为两个命令,并且仅在它看到第二个为空时才抱怨。这听起来不太可能,但你永远不会知道,所以无论如何我都会尝试去掉分号。 此外,您可能应该使用绑定参数进行调用,而不是在
sql
中嵌入值。 你还说在异常时会调用rollback,你有
utx.commit()
,但这也是函数中提交的冗余。     
由于函数返回1,这表示第一次删除抛出异常。这导致控制切换到
EXCEPTION
块,它只是返回。第一次删除后的其他代码都不应该执行。 异常处理程序是可怕的,因为它捕获任何异常,丢弃它,并返回一个标志值,告诉你很少发生了什么。它只比
WHEN OTHERS THEN NULL;
略好一点。在编写本文时,您无法知道发生了什么异常。应该删除异常处理程序(以便调用代码可以以某种方式捕获和处理异常),或者重写以至少以某种方式记录实际异常消息(SQLERRM)。 最明显的猜测是引发异常,因为执行代码的模式对其他模式中的表没有删除访问权限。可能相关的一个Oracle怪癖是存储的PL / SQL代码(例如此函数)无法利用通过角色授予的访问权限。必须直接向用户授予对其他模式对象的任何访问权限。     
此过程中的异常处理程序不是特别有用。它完全隐藏了Oracle正在抛出的错误消息。如果完全消除异常处理程序,那么错误堆栈是什么? 我的猜测是该过程的所有者没有从
npa_collaudo.documento_raccomandata
表中删除行的权限。但是,如果不知道实际引发了什么异常,就不可能知道。     

要回复问题请先登录注册