Perché ho bisogno di Transaction in Hibernate per operazioni di sola lettura?


107

Perché ho bisogno di Transaction in Hibernate per operazioni di sola lettura?

La seguente transazione pone un blocco nel DB?

Codice di esempio da recuperare dal DB:

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Posso usare al session.close() posto di tx.commit()?


9
La transazione è richiesta dal DB stesso. Puoi leggere informazioni sulla modalità autocommit qui: community.jboss.org/wiki/…
Bhesh Gurung

@BheshGurung immagino che richiediamo la trascrizione solo per l'operazione di scrittura
user93796

4
Hai letto la parte "Sfatare i miti del commit automatico" nel link?
Bhesh Gurung

Risposte:


131

Potresti effettivamente avere motivi per contrassegnare le transazioni come di sola lettura.

  1. Le transazioni per la lettura potrebbero sembrare davvero strane e spesso le persone non contrassegnano i metodi per le transazioni in questo caso. Ma JDBC creerà comunque la transazione, è solo che funzioneràautocommit=true se un'opzione diversa non è stata impostata esplicitamente.
  2. Ma non è garantito che il tuo metodo non scriva nel database. Se contrassegni il metodo come @Transactional(readonly=true), Spring imposterà la transazione JDBC in modalità di sola lettura, quindi dovrai stabilire se è effettivamente possibile scrivere nel DB nell'ambito di questa transazione. Se la tua architettura è ingombrante e alcuni membri del team possono scegliere di inserire query di modifica dove non è previsto, questo flag ti indirizzerà al punto problematico.
  3. Anche le transazioni di sola lettura possono essere ottimizzate dai DB, ma questo ovviamente è specifico del DB. Ad esempio, MySQL ha aggiunto il supporto per questo solo in InnoDB a partire dalla versione 5.6.4.
  4. Se non stai utilizzando JDBC direttamente, ma piuttosto un ORM, potrebbe essere problematico. Ad esempio, la comunità di Hibernate afferma che lavorare al di fuori della transazione potrebbe causare comportamenti imprevedibili. Questo perché Hibernate aprirà la transazione, ma non la chiuderà da sola, quindi la connessione verrà restituita al Connection Pool con la transazione non confermata. Cosa succede allora? JDBC mantiene il silenzio, quindi questo è specifico dell'implementazione (MySQL ripristina la transazione, Oracle afair la esegue il commit). Questo può anche essere configurato a livello di Connection Pool (ad es. C3P0 offre tale opzione, rollback per impostazione predefinita).
  5. Un'altra cosa quando si tratta di Hibernate, Spring imposta FlushMode su MANUAL in caso di transazioni di sola lettura, il che porta ad altre ottimizzazioni come la mancanza di controlli sporchi.
  6. Potresti voler sovrascrivere o impostare esplicitamente il livello di isolamento della transazione. Ciò influisce anche sulle transazioni di lettura poiché vuoi o non vuoi leggere modifiche non salvate, essere esposto a letture fantasma, ecc.

Per riassumere: puoi andare in entrambe le direzioni, ma devi capire le conseguenze.


Grazie per la risposta Sto usando l'ibernazione (ibernazione nativa, non jpa) .Ma l'ibernazione mi costringe ad avviare una trascrizione prima di eseguire qualsiasi operazione di db.Se non ne avvio una, genera un errore dicendo che non è attiva alcuna tracscationn.Posso contrassegnare la trascrizione come di sola lettura , se si come?
user93796

Il flag readonly è effettivamente impostato per la connessione, non per la transazione stessa, e non puoi accedervi tramite Hibernate proprio così. È necessario utilizzare il supporto per le transazioni Spring e utilizzare le annotazioni o la configurazione transazionale basata su XML. In questo modo, Spring assume la proprietà della connessione e della gestione delle transazioni invece di Hibernate.
Stanislav Bashkyrtsev

1
Molto ben spiegato! Un altro articolo di Mark Richards spiega abbastanza bene le insidie ​​del flag di sola lettura nell'annotazione transazionale: ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh

48

Tutte le istruzioni del database vengono eseguite nel contesto di una transazione fisica, anche quando non dichiariamo esplicitamente i limiti della transazione (BEGIN / COMMIT / ROLLBACK).

Se non si dichiarano esplicitamente i limiti della transazione, ogni istruzione dovrà essere eseguita in una transazione ( autocommitmodalità) separata . Ciò può anche portare all'apertura e alla chiusura di una connessione per istruzione, a meno che l'ambiente non sia in grado di gestire l'associazione connessione per thread.

Dichiarare un servizio come @Transactionalti darà una connessione per l'intera durata della transazione e tutte le istruzioni useranno quella singola connessione di isolamento. Questo è molto meglio che non usare transazioni esplicite in primo luogo.

Su applicazioni di grandi dimensioni, potresti avere molte richieste simultanee e ridurre il tasso di richiesta di acquisizione della connessione al database migliorerà sicuramente le prestazioni complessive dell'applicazione.

JPA non applica le transazioni sulle operazioni di lettura. Solo le scritture finiscono per generare un'eccezione richiesta per la transazione nel caso in cui dimentichi di avviare un contesto transazionale. Tuttavia, è sempre meglio dichiarare i limiti delle transazioni anche per le transazioni di sola lettura (in primavera @Transactionalconsente di contrassegnare le transazioni di sola lettura, il che ha un grande vantaggio in termini di prestazioni).


1
"... allora ogni istruzione dovrà essere eseguita in una transazione separata". Il contenitore non esegue l' elaborazione batch automaticamente?
Arash

L'elaborazione batch è per le modifiche, non per la lettura dei dati. E anche così, il batch JDBC non è abilitato per impostazione predefinita quando si utilizza JPA e Hibernate.
Vlad Mihalcea

1
Grazie Vlad. Ho letto alcuni tuoi articoli. Sono davvero utili.
Arash

Questo stackoverflow.com/q/34797480/179850 sembra contraddire un po 'la tua affermazione che le transazioni di sola lettura hanno grandi vantaggi in termini di prestazioni. Almeno, non sembra essere il caso nel contesto dell'ibernazione.
nimai

No, non è così. Si tratta di impostare la sola lettura, mentre il mio consiste nell'evitare il commit automatico.
Vlad Mihalcea

17

Le transazioni in effetti messo serrature sul database - buoni motori di database gestire serrature concorrenti in un modo ragionevole - e sono utili con sola lettura utilizzano per garantire che nessun altra operazione aggiunge i dati che rende la visualizzazione incoerente. Desideri sempre una transazione (sebbene a volte sia ragionevole regolare il livello di isolamento, è meglio non farlo per cominciare); se non si scrive mai al DB durante la transazione, sia il commit che il rollback della transazione risultano uguali (e molto economici).

Ora, se sei fortunato e le tue query sul DB sono tali che l'ORM le associa sempre a singole query SQL, puoi farcela senza transazioni esplicite , affidandoti al comportamento di autocommit integrato del DB, ma gli ORM sono sistemi relativamente complessi quindi non è affatto sicuro fare affidamento su tale comportamento a meno che non si lavori molto di più per controllare cosa fa effettivamente l'implementazione. Scrivere i limiti della transazione esplicita è molto più facile da ottenere (specialmente se puoi farlo con AOP o con una tecnica simile basata su ORM; da Java 7 in poi si potrebbe usare anche try-with-resources suppongo).


14

Non importa se leggi o meno: il database deve comunque tenere traccia del tuo gruppo di risultati, perché altri client di database potrebbero voler scrivere dati che cambierebbero il tuo gruppo di risultati.

Ho visto programmi difettosi per uccidere enormi sistemi di database, perché leggono solo i dati, ma non si impegnano mai, costringendo il registro delle transazioni a crescere, perché il DB non può rilasciare i dati della transazione prima di un COMMIT o ROLLBACK, anche se il client non ha fatto nulla per ore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.