Ho letto un po 'su come impostare le transazioni per collegare Spring e Hibernate insieme. Sembra che l'approccio raccomandato sia quello di inizializzare le transazioni nel livello di servizio.
Definitivamente. demarcazione transazione dovrebbe essere fatto a livello livello di servizio, non a livello dello strato DAO:
- l'unità di lavoro è il servizio, non il DAO
- si desidera una transazione per abbracciano molteplici i DAO, se necessario.
Quello che non mi piace è che esistono maggior parte delle transazioni solo perché sono necessari per Hibernate per funzionare correttamente.
È consigliabile elaborare questa parte perché le transazioni non sono specifiche di Hibernate.
E quando ho davvero bisogno di una transazione per un lavoro che chiama più metodi di servizio, sembra che non abbia una scelta per mantenere l'inizializzazione delle transazioni dai lavori.
Se si desidera chiamare più servizi all'interno di una transazione avviata dallo strato di lavoro, dichiarare i propri servizi come transazionale con REQUIRED
la semantica (il default) e si basano sulla propagazione delle transazioni primavera (questo vale a meno che non hai bisogno di una chiamata remota; in tal caso, utilizzare EJB).
Quindi spostare le annotazioni @Transactional da DAO al servizio non sembra fare alcuna differenza.
E fa fare la differenza e il fatto che è necessario per poter effettuare transazioni dallo strato di lavoro durante l'esecuzione batch non rende le cose diverse.
Consiglio vivamente di leggere lo Chapter 9. Transaction management.
(...) il mio problema principale deriva da Hibernate. Scusa se non ero chiaro.
Nessun problema. È solo che quando una domanda è vaga, si ottiene spesso una risposta vaga :)
Dalla documentazione di ibernazione: "Le transazioni di database non sono mai opzionali.Tutta la comunicazione con un database deve avvenire all'interno di una transazione.". Ecco perché gli sviluppatori mettono i metodi DAO transazionali sul mio progetto.
spiacenti ma la dichiarazione di cui sopra dice solo che il "comunicazione con un database deve avvenire all'interno di una transazione", niente di più, e decidere dove avviare la transazione è lasciato a vostra discrezione (in genere il servizio strato). Se lo fai a livello di DAO, cosa succede se chiama DaoFoo
e e DaoBar
non riesce? In questi casi, probabilmente vorrai eseguire il rollback di tutte le modifiche, non solo quelle eseguite in DaoBar
. Da qui la necessità di controllare la transazione in cui inizia l'unità di lavoro.
IMHO, gli sviluppatori hanno bisogno di guida.
Ciò significa che tutti i miei servizi dovrebbero essere transazionali? Anche quando leggo i dati, ad esempio?
Prima di tutto, vi suggerisco di leggere Non-transactional data access and the auto-commit mode (il fratello minore del Sessions and transactions) per chiarire le cose circa "operazioni di sola lettura". Leggendo l'intera pagina è valsa la pena, ma lasciatemi citare questa parte specifica:
molti sviluppatori di applicazioni pensano di possono parlare con una banca dati al di fuori di una transazione . Questo ovviamente non è possibile ; Nessuna istruzione SQL può essere inviata a un database esterno a una transazione del database. Il termine accesso non transazionale significa che non ci sono limiti di transazione espliciti , nessuna transazione di sistema e che il comportamento di accesso ai dati è quello della modalità autocommit . Ciò non significa che nessuna transazione di database fisico sia implicata nello .
Una volta terminato il collegamento sopra, la prossima lettura suggerita sarà @Transactional read-only flag pitfalls. Ecco la parte rilevante:
(...) La linea di fondo è che quando si utilizza un framework basato su ORM , il flag di sola lettura è inutile e nella maggior parte dei casi viene ignorato in . Ma se si ancora insistono sull'uso di esso, impostare sempre la modalità di propagazione ai supporti, come mostrato nel Listato 9, in modo da nessuna transazione viene avviata:
Listing 9. Utilizzo di sola lettura e SUPPORTS
modalità di propagazione per selezionare operazione
@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
Meglio ancora, basta evitare di utilizzare l'annotazione @Transactional
tutto quando fa operazioni di lettura, come illustrato.210 in 10:
Listing 10. Rimozione del @Transactional
annotazioni per selezionare operazioni
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
Ottima domanda e stavo per chiedere io stesso :) – willcodejavaforfood
Aiutare con una domanda non è così gratificante come aiuto con una risposta, ma è ancora buono da ascoltare; o) – Damien