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

Java 如何编写oracle函数来更新不同模式下的表,java,oracle,plsql,atomikos,Java,Oracle,Plsql,Atomikos,你好 我正在将wbsphere应用程序移植到tomcat,我必须在同一台服务器上的两个数据库上工作,并且我已经将tomcat与atomikos transactionessential集成在一起。这是我使用jta的第一个项目,oracle dba告诉我不需要xa和两阶段提交,因为模式在同一台服务器上。所以我对atomikos使用了非xa方法。 以下代码在单个架构上运行良好(按预期提交和回滚): 在另一个地方,调用下面的oracle函数并尝试更改两个模式,然后返回代码1。我不知道pl slq,但在

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

在另一个地方,调用下面的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”中发现了这段代码:

我把它改成:

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中删除了记录?

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


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

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


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

因为函数返回1,这表示第一次删除引发了异常。这将导致控制切换到
异常
块,该块仅返回。在第一次删除之后,不应执行任何其他代码

异常处理程序非常可怕,因为它捕获任何异常,丢弃它,并返回一个很少告诉您发生了什么的标志值。它只比别人为空时的
稍好一点。正如本文所写,您无法知道发生了什么异常。应该删除异常处理程序(以便调用代码能够以某种方式捕获和处理异常),或者重写异常处理程序,至少以某种方式记录实际的异常消息(SQLERRM)


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

因为函数返回1,这表示第一次删除引发异常。这将导致控制切换到
异常
块,该块仅返回。在第一次删除之后,不应执行任何其他代码

异常处理程序非常可怕,因为它捕获任何异常,丢弃它,并返回一个很少告诉您发生了什么的标志值。它只比别人为空时的
稍好一点。正如本文所写,您无法知道发生了什么异常。应该删除异常处理程序(以便调用代码能够以某种方式捕获和处理异常),或者重写异常处理程序,至少以某种方式记录实际的异常消息(SQLERRM)


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

您如何知道函数返回1?您抛出的异常没有报告
ret
值。调用本身可能已中断-请尝试删除尾随的
来自
sql
字符串。虽然您应该从
eseguiSP(sql)
中获得一个更有用的异常,如果是这样的话,但它可能隐藏在代码的其他地方(可能是进一步添加的东西使它看起来像是返回了1?);两个delete都不应该生效,除非它试图将其视为两个命令,并且只在看到第二个命令为null时才抱怨。这听起来不太可能,但你永远也不知道,所以我还是要试着去掉分号

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


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

您如何知道函数返回1?您抛出的异常没有报告
ret
值。调用本身可能已中断-请尝试删除尾随的
来自
sql
字符串。如果是这样的话,您应该从
eseguiSP(sql)
中获得一个更有用的异常,但它可能隐藏在代码中的其他地方(可能更进一步的东西是添加了一些东西,使它看起来像一个1 was ret)
//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);