Как написать функцию оракула для обновления таблиц на разных схемах - PullRequest
0 голосов
/ 30 марта 2011

привет, я портирую приложение wbsphere на tomcat, мне нужно работать над двумя базами данных на одном сервере, и я интегрировал tomcat с существенной транзакцией atomikos.Это мой первый проект с jta, и оракул 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?

Ответы [ 3 ]

3 голосов
/ 30 марта 2011

Поскольку функция возвращает 1, это будет означать, что первое удаление вызывает исключение.Это приводит к переключению управления на блок EXCEPTION, который просто возвращается.Никакой другой код после первого удаления не должен выполняться вообще.

Обработчик исключений ужасен, поскольку он перехватывает любое исключение, отбрасывает его и возвращает значение флага, которое очень мало говорит вам о том, что произошло,Это только немного лучше, чем WHEN OTHERS THEN NULL;.Поскольку это написано, у вас нет возможности узнать, что произошло исключение.Обработчик исключений должен быть либо удален (чтобы вызывающий код мог каким-то образом перехватить и обработать исключение), либо переписать, чтобы хотя бы каким-то образом зарегистрировать фактическое сообщение об исключении (SQLERRM).

Наиболее очевидное предположениезаключается в том, что возникает исключение, потому что схема, в которой выполняется код, не имеет доступа для удаления к таблице в другой схеме.Одна из особенностей Oracle, которая может иметь значение, заключается в том, что хранимый код PL / SQL (например, эта функция) не может использовать доступ, предоставляемый через роль.Любой доступ к объектам других схем должен быть предоставлен непосредственно пользователю.

2 голосов
/ 30 марта 2011

Обработчик исключений в этой процедуре не особенно полезен. Он полностью скрывает сообщение об ошибке, которое выдает Oracle. Если вы полностью исключите обработчик исключений, что такое стек ошибок?

Я предполагаю, что владелец процедуры не имеет прав на удаление строк из таблицы npa_collaudo.documento_raccomandata. Но невозможно знать это, не зная, какое исключение на самом деле возникает.

1 голос
/ 30 марта 2011

Откуда вы знаете, что функция возвращает 1? Исключение, которое вы выдаете, не сообщает о значении ret. Сам вызов может быть прерван - попробуйте удалить конечный ; из строки sql. Хотя вам следует получить более полезное исключение из eseguiSP(sql), если это так, но оно может быть скрыто в другом месте вашего кода (может быть, что-то еще дальше добавляет что-то, что выглядит как возвращаемая 1?); и ни одно из удалений не вступит в силу, если только оно не попытается обработать его как две команды, а только с жалобой увидит, что вторая пуста. Это звучит маловероятно, но вы никогда не знаете, поэтому я все равно попробую удалить точку с запятой.

Кроме того, вам, вероятно, следует использовать параметры связывания для вызова, а не встраивать значения в sql.

Вы также сказали, что откат будет вызываться при исключении, и у вас есть utx.commit(), но это также избыточно с фиксацией в функции.

...