2010-07-01 3 views
13

sto ottenendo questa eccezione in un controllore di un'applicazione web basata su framework primavera usando Hibernate. Ho provato molti modi per contrastarlo ma non ho potuto risolverlo.StaleObjectstateException riga è stata aggiornata o eliminata da

Nel metodo del controllore, handleRequestInternal, ci sono chiamate fatte al database principalmente per "leggere", a meno che non sia un'azione di invio. ho utilizzato, sessione di primavera, ma si trasferì a getHibernateTemplate() e il problema persiste.

in fondo, questa la seconda chiamata al database genera questa eccezione. Ovvero:

1) getEquipmentsByNumber(number) {innanzitutto un dispositivo viene prelevato dal DB in base al 'numero', che ha un elenco di proprietà e ogni proprietà ha un elenco di valori. I loop through quei valori (oggetti primitivi stringhe) per leggere in alle variabili)

2) getMaterialById(id) {recupera materiali a base di id}

Capisco che la seconda chiamata, molto probabilmente, sta facendo la sessione "filo", ma sono solo oggetti 'lettura', allora perché la seconda chiamata genera l'eccezione stato dell'oggetto stantio sulla proprietà Equipaggiamento se non è cambiato nulla?

non può cancellare la cache dopo la chiamata dal momento che provoca LazyExceptions su oggetti che passano alla vista.

Ho letto questo: https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0 ma non ho potuto risolvere il problema in base ai suggerimenti forniti.

Come posso risolvere questo problema? Tutte le idee e pensieri sono apprezzati.

UPDATE: Quello che ho appena provato è che nella funzione getEquipmentsByNumber() dopo aver letto le variabili da un elenco di proprietà, faccio questo: getHibernateTemplate().flush(); e ora l'eccezione è su questa linea piuttosto che la chiamata per andare a prendere il materiale (che è getMaterialById(id)).

UPDATE: Prima di chiamare in modo esplicito a filo, sto rimuovendo l'oggetto dalla cache di sessione in modo che nessun oggetto stantio rimane nella cache.

getHibernateTemplate().evict(equipment); 
getHibernateTemplate().flush(); 

OK, ora il problema si è spostato al successivo richiamo da DB dopo che ho fatto questo. Suppongo di dover etichettare i metodi come sincronizzati e sfrattare gli oggetti non appena ho finito di leggere il loro contenuto! non suona molto bene.

UPDATE: Realizzato il metodo handleRequestInternal "sincronizzato". L'errore è scomparso. Ofcourse, non la soluzione migliore, ma cosa fare! processati in handleRequestInternal per chiudere la sessione corrente e aprirne uno nuovo. Ma farebbe sì che altre parti dell'app non funzionassero correttamente. Ho provato a usare ThreadLocal che non ha funzionato neanche.

+1

se è possibile inserire il codice per il metodo che genera l'eccezione, lo esaminerò ulteriormente. Sembra una specie di pesce – walnutmon

risposta

0

Questo problema era qualcosa che avevo sperimentato ed era piuttosto frustrante, anche se ci deve essere qualcosa di un po 'strano nelle chiamate DAO/Hibernate, perché se stai facendo una ricerca per ID non c'è motivo di ottenere uno stato scaduto, poiché si tratta di una semplice ricerca di un oggetto.

In primo luogo, assicurarsi che tutti i metodi sono annotati con @Transaction(required=true) // you'll have to look up the exact syntax

Tuttavia, questa eccezione è di solito gettati quando si tenta di apportare modifiche a un oggetto che è stato staccato dalla sessione è stato recuperato da. La soluzione a questo spesso non è semplice e richiederebbe più codice pubblicato in modo da poter vedere esattamente cosa sta succedendo; il mio suggerimento generale sarebbe quello di creare un @Service che esegua questo tipo di cose all'interno di una singola transazione

+0

Grazie per il suggerimento. Quello che ho appena testato è che nella funzione getEquipmentsByNumber dopo aver letto le variabili dall'elenco delle proprietà, faccio questo: getHibernateTemplate(). Flush(); e ora l'eccezione è su questa linea piuttosto che la chiamata a recuperare materiale (che è getMaterialById (id)) Non sto usando annotazioni poiché non mi è molto familiare. – Saky

2

Qui ci sono 3 possibilità (come non so esattamente, che tipo di gestione della sessione di ibernazione si sta utilizzando). Aggiungere uno dopo l'altro e testare:

Utilizzare la mappatura bidirezionale con inverse=true tra oggetto padre e oggetto figlio, in modo che la modifica in genitore o figlio venga propagata all'altra estremità della relazione in modo corretto.

Aggiungere il supporto per Optimistic Locking utilizzando TimeStamp o Version colonna

Usa unirsi interrogazione per andare a prendere l'intero grafo di oggetti [genitore + figli] insieme per evitare la seconda chiamata del tutto.

Infine, se e solo se non funziona nulla: carico del genitore nuovamente Id (avete già) ei dati popolano modificato quindi aggiornare.

La vita andrà bene! :)

+0

Penso che il suggerimento di usare l'inverso sia probabilmente confuso nel contesto della propagazione delle modifiche da genitore a figlio. Per questo il comportamento effettivo da configurare è "a cascata". Inversa come concetto è ortogonale alla cascata – Shailendra

3

Ho anche lottato con questa eccezione, ma quando ha continuato a ripetersi anche quando ho messo un blocco sull'oggetto (e in un ambiente di test, dove sapevo che ero l'unico processo che toccava l'oggetto), Ho deciso di dare alla traccia parentetica la traccia della debita considerazione.

org.hibernate.StaleObjectStateException: Riga è stato aggiornato o eliminato da un'altra operazione (o unsaved-value mappatura non era corretto): [com.rc.model.mexp.MerchantAccount # 59132]

Nel nostro caso si è scoperto che la mappatura era sbagliata; avevamo il type="text" nella mappatura di un campo che era un tipo di testo medio nel database, e sembra che Hibernate lo odia davvero, almeno in certe circostanze. Abbiamo rimosso del tutto le specifiche del tipo dalla mappatura per questo campo e il problema è stato risolto.

Ora la cosa strana è che nel nostro ambiente di produzione, con la mappatura apparentemente problematica, NON otteniamo questa eccezione. Qualcuno ha idea del perché questo potrebbe essere? Stiamo usando la stessa versione di MySQL - "5.0.22-log" (non so cosa significhi "-log") - negli sviluppatori di sviluppo e sviluppo.

5

Sei mis-usando Hibernate, in qualche modo, che induce a pensare che sei aggiornamento o eliminazione oggetti dal database.

Ecco perché chiamare flush() lancia un'eccezione.

Una possibilità: in modo errato "condivisione" Sessione o entità, tramite i campi membro del servlet o controller. Questo è il motivo principale per cui "sincronizzati" cambierebbe i tuoi sintomi di errore. Soluzione breve: non farlo mai. Sessioni ed entità non dovrebbero & non funzionano in questo modo - ogni richiesta dovrebbe essere elaborata indipendentemente.

Un'altra possibilità: unsaved-value imposta su 0 per i campi PK "int". Potresti essere in grado di digitare questi come "Integer", invece, se vuoi veramente usare 0 come valore PK valido.

Terzo suggerimento: uso Hibernate Session in modo esplicito, imparare a scrivere semplice codice corretto che funziona, quindi caricare la sorgente Java per Hibernate librerie/primavera in modo da poter leggere & capire che cosa queste librerie sono in realtà facendo per voi.