[Python] [Python e PostgreSQL] All'interno delle eccezioni, le transazioni si comportano diversamente?

Daniele Varrazzo piro a develer.com
Lun 25 Ott 2010 11:53:57 CEST


On Mon, 25 Oct 2010 00:00:34 +0200, Marco Fochesato <marcofoc a libero.it>
wrote:
>> Grazie per la versione. Vorrei vedere un pezzetto di codice con le
>> operazioni che svolgi: la query, l'eccezione, la query
>> *nell'*eccezione...

> try:
> 	cur.execute(update, (nuovo_valore, valore_statico))
>         connDB.commit()
> except psycopg2.IntegrityError:          
>         connDB = psycopg2.connect(connessione)
>         cur = connDB.cursor()

Se l'execute(update) può dare un'eccezione, puoi usare una transazione
annidiata con SAVEPOINT per mantenere la sessione integra:

    cur.execute("SAVEPOINT tmp;")
    try:
        cur.execute(update, (nuovo_valore, valore_statico))
    except psycopg2.IntegrityError:
        cur.execute("ROLLBACK TO tmp;")
        cur.execute( ... quello che fai on caso di errore)
    else:
        # quello che fai se non c'e' stato errore
    finally:
        connDB.commit()	
        cur.close()
        connDB.close()            

Vedi http://www.postgresql.org/docs/9.0/static/sql-savepoint.html per la
doc.

> Non ho mai postato del codice.. spero non si dovesse far in altra
> maniera.
> Le varie variabili, sono state dichiarate prima.. ma credo vadano bene
> tutte. Il problema è proprio nel primo update. Mi dà errore perchè
> cambio ina idnazione non ancora presente nella tabella nazioni..

Questo esempio non è quello che avrei definito auto-contenuto: stavamo
parlando di psycopg che si comporta in auto-commit in qualche condizione
collegata a creare connessioni nell'eccezione, no? Speravo in codice che
testasse solo questo :) 

Io per conto mio ho provato:

    import psycopg2
    
    def test(dsn):
        """test if a connection created in an exception handler goes
autocommit"""
        cnn = psycopg2.connect(dsn)
        cur = cnn.cursor()
    
        cur.execute("""drop table if exists test;""")
        cur.execute("""create table test (data int primary key); insert
into test values (1);""")
        cnn.commit()

        # make an error
        try:
            cur.execute("""insert into test values (1)""")
        except psycopg2.IntegrityError:
            # connection created in the handler
            cnn2 =  psycopg2.connect(dsn)
            cur2 = cnn2.cursor()
            cur2.execute("""insert into test values (2)""")
    
        # was cnn2 autocommit?
        cnn3 = psycopg2.connect(dsn)
        cur3 = cnn3.cursor()
        cur3.execute("select count(*) from test where data = 2")
        n = cur3.fetchone()[0]
    
        assert n == 0, "connection in exception handler autocommit"
    
        # double check
        cnn2.commit()
        cur3.execute("select count(*) from test where data = 2")
        n = cur3.fetchone()[0]
        assert n == 1
    
        print "ok"
    
    test("dbname=test")

Ma questo test, nelle mie condizioni passa. Io ho sottomano solo una
versione di sviluppo di psycopg: posso provare più tardi con quella che usi
tu, ma se riesci a creare la condizione che fa fallire l'assert col tuo
setup allora possiamo dire che c'è un bug. Altrimenti non si sa :)


-- 
Daniele Varrazzo - Develer S.r.l. 
http://www.develer.com


Maggiori informazioni sulla lista Python