Log in

View Full Version : JDBC - DB Oracle - Transazioni



NoeX
5th January 2009, 23:12
Holà, ho un dubbio sull'integrità dei dati quando più utenti operano sulla stessa tabella del database.

JDBC utilizza le transazioni a livello di database, quando il developer vuole eseguire più statement SQL in cascata pone a falso l'autocommit di JDBC e al termine degli statement fà il commit e OK.

Nel caso io abbia due utenti, quindi due sessioni, quando faccio la select del valore corrente della sequenza, una mi restituisce X e l'altro X+1 e va bene.

Nel caso io abbia queste due sessioni X e Y:

X: fà una select sulla tabella

Y: fà una delete di una riga presente nella select di X

Quando X arriva alla riga cancellata, X la vede ancora nella sua sessione ma nella sessione di Y non è presente, che succede ?
X ne leggerà i valori, ma se mai dovesse fare l'update di quella riga ritorna una SQL Exception perchè la vecchia transazione è stata chiusa e ne è stata aperta una nuova con i dati aggiornati ?

San Vegeta
5th January 2009, 23:21
non ci ho mai provato quindi non ne sono sicuro al 100%, però non dovrebbe essere strano che X non trovi più la riga... alla fine la sequenzialità è stata rispettata... se non vuoi interferenze a livello di table devi lockare la tabella intera

NoeX
6th January 2009, 11:27
neanche io ci ho mai provato ma ho questo dubbio. Quindi tu dici di modificare l'ISOLATION level della connessione ?

Tanek
6th January 2009, 12:31
Ma se c'è una sessione aperta (Y, che ha l'autocommit=false) la tabella è lockata, quindi se cerchi di fare una update comunque su quella tabella ti restituisce una SQLException, no?

Fai una bella cosa, prima di fare l'update di X rifai la select (tanto l'id del record ce l'hai già) così ti gestisci come ti pare il fatto che possa essere "sparito" il record tramite le operazioni di un altro utente.

Uhm mi sono appena svegliato, in caso abbia detto cazzate mi correggo più tardi :sneer:
(cheppalle, domani si ricomincia :cry: )

San Vegeta
7th January 2009, 10:38
fermi.
State facendo confusione.

L'isolamento delle sessioni e i lock sono due cose distinte e gestiti sia a livello di driver jdbc che a livello di DB.

JDBC dice chiaramente di non fare affidamento al 100% sulla gestione dell'autocommit perchè i settaggi del Database hanno la precedenza.

Oracle permette di fare una roba tipo "Lock tabella - query - Release lock" come una singola transazione. Se non erro, ma non mi ricordo più, è possibile fare lo stesso per una sessione.

Ora tu parli di 2 sessioni (occhio che due sessioni Oracle non sono la stessa cosa di due connessioni al db) in cui in una viene fatta una select e in una un update.

Se la sessione X fa la select e la sessione Y fa la update, possono presentarsi i seguenti scenari

X esegue
Y esegue
chi scorre il resultset di X ad un certo punto troverà un record modificato da Y

Y esegue
X esegue
chi scorre il resultset di X non avrà nessun problema di coerenza dei dati perchè l'update assicura il lock della tabella per l'intera esecuzione della transazione.

Se vuoi essere sicuro che chi scorre il resultset di X non abbia incoerenze, devi fare in modo di lockare la tabella prima della select, fare la select, scorrere tutto il resultset e fare le operazioni del caso, rilasciare il lock. In questo caso, Y non viene eseguita finchè non viene rilasciato il lock e probabilmente da pure errore di timeout se resta in attesa troppo tempo.

Gate
7th January 2009, 11:41
Y esegue
X esegue
chi scorre il resultset di X non avrà nessun problema di coerenza dei dati perchè l'update assicura il lock della tabella per l'intera esecuzione della transazione.
* (anche se lokki solo quello che modifichi, anche a livello di riga)
se fai una update e non committi, la modifica e' solo della sessione mi pare e con una select vedi il dato non modificato
se committi crei un lock e chi fa select subito dopo vede il dato modificato

Tanek
7th January 2009, 12:17
Si ma il lock del commit è infinitesimo in termini di tempo, e soprattutto non è vincolante su una SELECT di un altro utente/sessione (come hai detto tu) che però è il caso che serve a Noex, no?

Boh, non vorrei aver capito male il problema :)

San Vegeta
7th January 2009, 12:48
allora:
il lock della tabella è un lucchetto che viene messo alla tabella e può essere in lettura o lettura/scrittura.

quando c'è il lock, solo l'id che ha messo il lock può fare qualosa sulla tabella, compatibilmente col tipo di lock (se è un lock in lettura, tutti possono leggere ma scrive solo chi blocca, se è un lock in scrittura, ogni accesso è vietato tranne che a chi blocca)

se io inizio una transazione, apro un lock, aspetto 50 minuti e rilascio il lock, il lock dura 50 minuti.

a seconda del tipo di lock, un altro id (indifferente se sia nella stessa sessione o meno) può o non può fare select sulla tabella.
Se può fare select vuol dire che il lock è in lettura e che può leggere di record che stanno per essere aggiornati, quindi trovare incoerenze.
Se è un lock in scrittura, la query viene fatta o prima o dopo gli update, quindi il contenuto della select dipende dalla sequenzialità delle operazioni.

dal punto di vista del database è tutto coerente, dal punto di vista applicativo è incoerente ma è l'applicazione che deve preoccuparsi della sincronizzazione, il database si preoccupa della coerenza dei dati a livello di transazione.

Gate
7th January 2009, 12:54
generalmente i lock in lettura sono shared, ha poco senso lockare in exclusive per una select.

NoeX
7th January 2009, 13:00
Ho notato anche una altra cosa per quanto riguarda l'impostazione dei Result Set di JDBC, è la concorrenza, se definisci il Result Set concur updatable vuol che dire sono possibili modifiche, anche se credo che questa definizione sia più una hint al driver e dipendente dal db utilizzato.
Il mio era giusto un dubbio sull'esatta sequenza degli statements, la parte database all'univ è stata veramente molto carente, è stato trattato SQL con relativi JOIN e bla, ma sulle transazioni e sul funzionamento sono stati moltooo rapidi...
Esatto Tanek, fintanto che il commit dell'update (diciamo update per dire statements update\delete\insert, insomma gli statements che non ritornano niente) non è inviato, la sessione che ha fatto la select che dati vede ?
----------------------
La sequenza delle operazioni quindi è la seguente ?



X fà select
il DB mette il lock che abilita le letture, ma non le scritture (CREW)
il db rilascia il lock quando lo statement select è concluso e prende dalla coda degli statements l'update (*)
il db prende il lock exclusive write,esegue lo statement update e rilascia lock (**)


(*) conclusione statement select intendo non che l'applicazione ha effettuato lo scrolling di tutti i dati e chiuso il result set bensì che il risultato della select è pronto per essere elaborato dall'applicazione. (Dove è messo fisicamente il risultato della select ? In una variabile associata alla sessione dello user che ha fatto la select ?

(**) Corollario del (*):

se Y non ha fatto il commit, allora il dato di X è quello recuperato dalla select, il fetch dei dati da parte di X non è bloccato, perchè non c'è un lock.
Se Y fà il commit avviene un problema di incoerenza perchè i dati recuperati dalla select di X sono sporchi, quindi che succede ?
Dipende dalla configurazione che uno sceglie se rendere visibili le modifiche o meno ?


Attimo che mi rileggo tutti i vs commenti, grazie per le risposte intanto

P.S.:
Connessione != Sessione ?
Why ? Ti connetti con usr\psw e si apre una nuova sessione, è possibile che in una connessione al db vi siano anche più sessioni ?

San Vegeta
7th January 2009, 13:37
a seconda del DB, una sessione può essere condivisa da N connessioni.

Se non sbaglio in Oracle la sessione non è altro che un isolation level più alto e serve per una sorta di caching dei dati... all'interno di una stessa sessione le operazioni fatte senza commit danno risultati uguali alle stesse operazioni committate, ma non mi sono mai preoccupato più di tanto per comprendere bene il resto.

fatto sta che lo scrolling del resultset non dipende dai lock delle tabelle: il risultato è da qualche altra parte per lasciare la tabella libera il prima possibile.

se fai il fetch di un record che non esiste più probabilmente vedi il record ma se poi provi a fare una roba del tipo

select * from A where id = x non ti verrà restituito nulla... ovviamente se usi quell'id per fare delle scritture gli errori saran diversi...