2016-11-07 3 views
0

Ich habe einen Code-Block, der einige Zeit braucht, um zu beenden, und ich habe eine Fortschrittsvariable in einer Tabelle erstellt, die der Prozess aktualisiert, damit der Endbenutzer wissen kann, wie viel noch zu vervollständigen ist.Konflikt zwischen Savepoint und Commit

Die Sache ist, dass der Codeblock als eine atomare Transaktion behandelt wird, so dass der Wert der Fortschrittsvariable nur 0% oder 100% anzeigt, es sei denn, ich verwende die commit Anweisung, die einen an einem früheren Punkt deklarierten Savepoint entfernt blockieren, und wenn eine Ausnahme auftritt, wird sie nicht als gültig erkannt.

Der Code ist so etwas wie dieses:

begin 
    /*do some stuff*/ 
    savepoint p_savepoint; 
    for q in (somequery) loop /*Really long loop*/ 
      /*Do some other stuff*/ 
      update t_sys_state set p1_progress = percentage 
      where user_id = 'theuserid'; 
      commit; /*This commit make the real progress value available*/ 
    end loop; 
    exception 
      when others then 
        rollback to p_savepoint; /*This savepoint is not recognized because of the previous commit*/ 
        raise; 
end; 

Gibt es eine Möglichkeit, um dieses?

+4

Wenn Sie nur den Fortschritt Ihrer Schleife zeigen möchten Sie vielleicht prüfen wollen mit 'dbms_application_info' statt, die Sie diese Informationen in' v $ session_longops' setzen können, finden Sie z.B hier: http://stackoverflow.com/a/40154203/330315 –

+0

@a_horse_with_no_name danke, ich werde es morgen versuchen. – Typo

Antwort

3

Es klingt wie Sie Ihren Fortschritt in einer autonomen Transaktion aktualisieren möchten. Dies ist eine der sehr, sehr wenigen Situationen, in denen die Verwendung einer autonomen Transaktion sinnvoll ist.

CREATE OR REPLACE PROCEDURE log_progress(p_user IN varchar2, 
              p_percentage IN number) 
AS 
    PRAGMA autonomous_transaction; 
BEGIN 
    UPDATE t_sys_state 
    SET p1_progress = p_percentage 
    WHERE user_id  = p_user; 
    commit; 
END; 

und dann

begin 
    /*do some stuff*/ 
    savepoint p_savepoint; 
    for q in (somequery) loop /*Really long loop*/ 
      /*Do some other stuff*/ 
      log_progress('theuserid', percentage); 
    end loop; 
    exception 
      when others then 
        rollback to p_savepoint; /*This savepoint is not recognized because of the previous commit*/ 
        raise; 
end; 
+0

schön, ich werde es morgen bei der Arbeit versuchen, danke. – Typo

Verwandte Themen