Domanda

Questa è una versione specifica di questa domanda .
Voglio verificare se sto inserendo una riga duplicata. Devo verificarlo a livello di codice nel mio livello di applicazione:

if (exists(obj))
{
    throw new DuplicateObjectException();
}
HibernateSessionFactory.getSession().save(obj);

o dovrei cogliere l'eccezione generata dal livello del database e attivata quando violo il contrappunto?

try
{
    HibernateSessionFactory.getSession().save(obj);
}
catch(ConstraintViolationException e)
{
    throw new DuplicateObjectException();
}

MODIFICA: In altre parole: anche se il vincolo è lì per rimanere (è comunque un buon design del database e non posso essere sicuro che la mia app sarà l'unica ad accedere al tavolo) dovrei fare affidamento sul vincolo e gestire l'eccezione sollevata dalla sua violazione, o è meglio verificare comunque?

EDIT2: Ovviamente controllo + inserisco all'interno di una transazione, bloccando la tabella per assicurarmi che nessun altro processo stia scrivendo un altro record nel frattempo

È stato utile?

Soluzione

Innanzitutto, devi avere una chiave primaria o un vincolo univoco sul database per applicare correttamente questa unicità - nessuna domanda.

Dato che il vincolo esiste, in che modo dovresti codificare nell'applicazione? La mia preferenza sarebbe quella di provare l'inserimento e catturare le eccezioni. Poiché presumibilmente la maggior parte degli inserimenti avrà esito positivo, solo alcuni falliranno come duplicati (questo è ciò che implica "eccezione"!): È inefficiente eseguire un controllo esistente prima di ogni inserimento, quando il database eseguirà comunque il proprio controllo dei vincoli .

Inoltre, è teoricamente possibile che il controllo esistente sia comunque sbagliato - se qualcun altro riesce a eseguire il commit di un record con lo stesso valore chiave nel piccolo intervallo tra il controllo esistente e l'inserimento. Quindi, se non si intercetta l'eccezione del database, si crederà che l'inserimento abbia avuto esito positivo, mentre in realtà non lo è stato.

Altri suggerimenti

Verifichi che l'oggetto esiste solo nel codice dell'applicazione e poi, una volta verificato che non lo fa, salvi beato l'oggetto. Ma un altro client simultaneo potrebbe inserire il proprio oggetto nel momento tra le due righe di codice. Quindi otterresti comunque un'eccezione duplicata, solo che questa volta non la prendi.

Devi fare il salvataggio () e prendere l'eccezione. Altrimenti hai una race condition con altri client simultanei che lavorano sullo stesso database.

È necessario rilevare l'eccezione del database a meno che non sia possibile garantire che l'applicazione sia l'unica che inserisce mai righe (e non inserirà mai righe) nel database.

MODIFICA: Potrei aver frainteso la domanda, ma direi comunque che l'opzione B (HibernateSessionFactory genera ConstraintException dal database) è l'opzione migliore. C'è sempre una piccola possibilità che un'altra applicazione possa inserire qualcosa nel tempo tra il controllo e l'effettiva chiamata di funzione. Inoltre, l'unico modo per verificare la presenza di un duplicato è eseguire una query aggiuntiva che è solo un inutile drenaggio delle prestazioni.

La mia comprensione originale della domanda era che nell'opzione A il controllo dupe sarebbe stato eseguito internamente (cioè utilizzando solo le strutture di dati che il programma aveva già creato e senza query fino a INSERT). La mia risposta originale era in risposta a questo metodo.

In generale, cerco di evitare la codifica che si basa su errori generati perché ho fatto qualcosa di sbagliato. A volte, però, è tutto ciò che puoi fare. Nella tua situazione, penso che dovresti controllare prima.

Questo si interromperà (consentendo voci duplicate) se il vincolo viene eliminato per qualche motivo (in genere lavori di manutenzione in cui il DBA trascura di riattivarlo). È necessario verificare questa situazione all'interno dell'applicazione.

Tuttavia, è buona norma progettare un database che imponga al database di imporre il vincolo (come è stato giustamente sottolineato), poiché altri potrebbero utilizzare il database. Come generalizzazione, è meglio supporre che le applicazioni e i database vivano in una relazione M: M: questo avverrà quasi sempre.

Le eccezioni generate da Hibernate (o qualsiasi componente ORM) tendono ad essere difficili da interpretare.

Se l'eccezione ha informazioni sufficienti per poter produrre un messaggio di errore che aiuta effettivamente l'utente, basta catturare l'eccezione, analizzarla e andare avanti.

Se l'eccezione non dispone di informazioni sufficienti, è necessario verificare la condizione di errore e generare un utile messaggio di errore per l'utente che sta facendo qualcosa di sbagliato.

La domanda è una di "quanto è opaca l'eccezione"? Alcuni sono piuttosto opachi. Altri hanno abbastanza da poter analizzare la stringa di messaggio e capire cosa dire all'utente.

Una volta che l'ibernazione genera un'eccezione dalla sessione, devi scartare la sessione (vedere la sezione 11.2.3). Pertanto, se è necessario verificare la presenza di duplicati e continuare a utilizzare la stessa sessione, non si ha altra scelta che verificare prima nell'applicazione.

Inoltre c'è una possibilità con il codice nel primo frammento che un altro processo potrebbe inserire un record che provocherebbe il lancio dell'eccezione duplicata tra il momento in cui si controlla il record duplicato e il momento in cui viene effettivamente inserito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top