2011-03-30 9 views
0

안녕하세요 나는 Tomcat에 wbsphere 애플리케이션을 포팅하고 있습니다. 동일한 서버에서 두 개의 데이터베이스로 작업해야하며 atomikos transactionessential으로 tomcat을 통합했습니다. 이것은 jta가있는 첫 번째 프로젝트이며 oracle dba는 스키마가 동일한 서버에 있으므로 xa와 2 단계 커밋이 필요 없다고 말했습니다. 그래서 나는 atomikos와 non-xa 접근법을 사용했습니다. 다음 오라클 함수가 호출 모두 스키마를 변경하려고 도착, 다른 곳에서다른 스키마의 테이블을 업데이트하는 oracle 함수를 작성하는 방법

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(); 

를, 그리고 코드 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); 

N 그것은 잘 작동합니다 (또는 적어도 0을 반환합니다). 왜 raccomandata_out에서 레코드를 삭제하더라도 코드의 이전 부분은 항상 1을 반환합니까?

답변

1

함수가 1을 반환하는 것을 어떻게 알 수 있습니까? 던지고있는 예외는 ret 값을보고하지 않습니다. 호출 자체가 손상되었을 수 있습니다. ;sql 문자열에서 제거해보십시오.이 경우에 eseguiSP(sql)에서 더 유용한 예외를 가져야하지만 코드의 다른 부분에 숨겨져있을 수 있습니다 (어쩌면 그 이상이 1이 반환 된 것처럼 보이는 무언가를 추가하는 것일 수 있습니다). 두 명령을 두 개의 명령으로 처리하려고 시도하고 두 번째 명령이 null 일 때만 불평하는 경우가 아니면 삭제가 적용되지 않아야합니다. 그럴 것 같지는 않지만 결코 알지 못하기 때문에 어쨌든 세미 콜론을 제거하려고합니다.

sql에 값을 포함시키지 말고 통화에 바인드 매개 변수를 사용해야합니다.

또한 롤백은 예외로 호출되며 사용자는 utx.commit()이긴하지만 함수의 커밋과 중복됩니다.

+0

게시물에 감사드립니다. 몇 가지 사실을 눈치 챘습니다 (편집 참조). 나는 그것이 어디 executeIpdate (레코드 1 삭제) 호출 때문에 returnig 1 것 같아요. –

+0

와우. 익명 블록은 아무 것도하지 않으므로 함수에서 반환 된'ret' 값은 무시됩니다. 'retValue = 1'은 아마도'executeUpdate()'에서 영향을받은 행의 수를 반환하지만 아마도 3 개 ('idLotto! = 0')의 DML 문을 다루는 방법에 대해서는 확신하지 못합니다. idLotto가 0이 아니고 유효하지 않거나 삭제할 것이 없으며'idLotto'가 0 인 경우 아마도 0을 반환합니다. 그럼에도 불구하고 왜 세미콜론이 필요한지 설명합니다 ... –

2

이 절차의 예외 처리기는 특히 유용하지 않습니다. 그것은 오라클이 던지고있는 오류 메시지를 완전히 숨기고 있습니다. 예외 처리기를 완전히 제거하면 오류 스택은 무엇입니까?

내 생각 엔 프로 시저 소유자가 npa_collaudo.documento_raccomandata 테이블에서 행을 삭제할 수있는 권한이 없다고 생각합니다. 그러나 실제로 어떤 예외가 발생했는지 알지 못하는 것을 알기 란 불가능합니다.

3

함수가 1을 반환하므로 첫 번째 삭제가 예외를 throw하고 있음을 나타냅니다. 이로 인해 제어가 EXCEPTION 블록으로 전환되며 이는 단순히 반환됩니다. 첫 번째 삭제 이후 다른 코드는 전혀 실행되지 않아야합니다.

예외 처리기는 예외를 잡아 버리고 폐기하고 발생한 상황을 거의 알려주지 않는 플래그 값을 반환한다는 점에서 끔찍한 처사입니다. WHEN OTHERS THEN NULL;보다 약간 낫습니다. 이것이 작성되었으므로 어떤 예외가 발생했는지 알 길이 없습니다. 예외 핸들러는 제거되어야하므로 (호출 코드가 어떤 식 으로든 예외를 포착하고 처리 할 수 ​​있음) 적어도 실제 예외 메시지 (SQLERRM)를 로그하는 방식으로 다시 작성해야합니다.

가장 명백한 추측은 코드가 실행되는 스키마에 다른 스키마의 테이블에 대한 삭제 액세스 권한이 없으므로 예외가 발생한다는 것입니다. 관련성이있는 오라클의 단점 중 하나는 저장된 PL/SQL 코드 (예 :이 함수)가 역할을 통해 부여 된 액세스를 이용할 수 없다는 것입니다. 다른 스키마 객체에 대한 액세스는 사용자에게 직접 부여되어야합니다.

+0

나는 예외 처리기를 제거 할 것입니다. (dba에 대한 공식적인 요청을하기 때문에 먼 길입니다). 그러나 나는 교부금을 검사하고 npa_collaudo 소유자는 다른 db 소유자에게 모든 특권을 부여했다. 나를 실망하게 만드는 것은 다음과 같이 삭제되고 실행되고 커밋되는 것입니다. 그것은 내가 아닌 xa datasource로 구성한 atomikos 데이터 소스 때문일 수 있습니까? –

관련 문제