2009-11-16 12 views
6

Qual è il modo migliore in PHP per gestire le eccezioni di chiavi esterne in un database MySQL? Esiste una classe mysql che può essere utilizzata per semplificare qualsiasi codice?Gestione delle eccezioni di chiave esterna in PHP

Idealmente, quello che voglio fare, ad esempio, è provare ad eliminare un record in cui è la chiave esterna a un numero qualsiasi di tabelle figlio. La chiave esterna getta l'eccezione, quindi mi piacerebbe essere in grado di esaminare ogni tabella di chiavi esterne e testarla, dando un feedback significativo sulle tabelle e il numero di record che causano l'eccezione. Questo verrà quindi restituito come errore in modo che l'utente finale possa fare riferimento ed eliminare i record incriminati.

risposta

6

Il modo in cui gestisco questo è impostare la mia classe wrapper del database per generare sempre un'eccezione quando si verifica un errore del database. Così, per esempio, potrei avere una classe chiamata MySQL con le seguenti funzioni:

public function query($query_string) 
{ 
    $this->queryId = mysql_query($query_string,$this->connectionId); 
    if (! $this->queryId) { 
     $this->_throwException($query_string); 
    } 
    return $this->queryId; 
} 

private function _throwException($query = null) 
{ 
    $msg = mysql_error().". Query was:\n\n".$query. 
       "\n\nError number: ".mysql_errno(); 
    throw new Exception($msg,mysql_errno()); 
} 

Ogni volta che una query non riesce, un'eccezione PHP regolare viene generata. Si noti che vorrei buttarli anche da altri posti, come una funzione connect() o una funzione selectDb(), a seconda che l'operazione abbia avuto o meno esito positivo.

Con questa configurazione, sei a posto. Qualsiasi posto che ci si aspetta che potrebbe essere necessario per essere la gestione di un errore del database, fare qualcosa di simile al seguente:

//assume $db has been set up to be an instance of the MySQL class 

try { 
    $db->query("DELETE FROM parent WHERE id=123"); 
} catch (Exception $e) { 
    //uh-oh, maybe a foreign key restraint failed? 
    if ($e->getCode() == 'mysql foreign key error code') { 
     //yep, it failed. Do some stuff. 
    } 
} 

Modifica

In risposta al commento del manifesto qui sotto, avete alcune informazioni limitate a disposizione per aiutare a diagnosticare un problema chiave estera. Il testo di errore creato da un vincolo di chiave esterna non è riuscito ed è tornato da mysql_error() simile a questa:

Cannot delete or update a parent row: 
a foreign key constraint fails 
(`dbname`.`childtable`, CONSTRAINT `FK_name_1` FOREIGN KEY 
(`fieldName`) REFERENCES `parenttable` (`fieldName`)); 

Se le chiavi esterne sono abbastanza complesso che non si può essere sicuro di quello che potrebbe causare un errore di chiave esterna per una data query, quindi potresti probabilmente analizzare questo testo di errore per aiutarti a capirlo. Il comando SHOW ENGINE INNODB STATUS restituisce un risultato più dettagliato anche per l'ultimo errore di chiave esterna.

Altrimenti, probabilmente dovrai scavare da solo. La seguente query vi darà un elenco di chiavi esterne su una determinata tabella, che è possibile esaminare per informazioni:

select * from information_schema.table_constraints 
WHERE table_schema=schema() AND table_name='table_name'; 

Purtroppo, non credo che ci sia una bacchetta magica per la soluzione diversa da esaminare gli errori e vincoli molto attentamente.

+0

Questo sembra un buon modo per controllare strutturalmente la gestione degli errori, ma voglio davvero scoprire se posso elencare dinamicamente le tabelle figlio e poi interrogarle per elencare le eccezioni attuali. Quindi è il po 'dentro "Fai qualcosa" con cui sto lottando. :) – Das123

+0

Questo è quasi identico al mio approccio. –

+0

Fantastico. Grazie. :) Le informazioni extra completano l'immagine per me. :) – Das123

0

Penso che la soluzione migliore sarebbe fare un transaction. In questo modo, l'inserimento sarà sempre valido o non eseguito affatto. Questo può restituire un messaggio di errore con cui puoi lavorare. Questo ti impedirà di dover controllare manualmente ogni tabella - il db lo fa per te.

+0

Grazie per la risposta, ma da quello che ho capito la transazione confeziona solo le query. Quello che voglio fare è, dopo che l'eccezione si è innescata, dare un feedback significativo dei record figli effettivi che hanno causato l'eccezione. – Das123