Ho davvero bisogno di trigger per il database relazionale, ad esempio PostgreSQL?


10

So che i trigger possono essere utilizzati per convalidare i dati memorizzati per mantenere coerente il database. Tuttavia, perché non eseguire la convalida dei dati sul lato dell'applicazione prima di memorizzarli nel database?

Ad esempio, archiviamo i client e vogliamo eseguire alcune convalide che non possono essere facilmente eseguite a livello di DDL. https://severalnines.com/blog/postgresql-triggers-and-stored-function-basics

Un altro esempio è l'audit.

Aggiornare

In che modo i trigger e le transazioni del database funzionano insieme. Ad esempio, se desidero eseguire la convalida dei dati inseriti. È fatto all'interno di una transazione. Cosa succede prima: la transazione è impegnata o il trigger viene eseguito?


However, why not perform validation of data on the application side before storing them into the database?bene, questi due non si escludono a vicenda. È probabile che tu convalidi cose diverse su entrambi i lati. Mentre le convalide sul lato dell'applicazione sono incentrate sul business, le convalide sul database sono più incentrate sui dati. Pensa in un database alimentato da diverse e diverse applicazioni.
Laiv

Dovrai inserire dati da una fonte esterna che sta semplicemente eseguendo un dump di dati senza cervello nel tuo sistema? In tal caso, potresti avere casi in cui è necessario inserire i dati in un formato non valido per la correzione in un secondo momento. In questo caso, i trigger causeranno problemi infiniti. Basta tenerlo a mente. A volte non si desidera eseguire un trigger.
Greg Burghardt,

L'aggiornamento dovrebbe essere una domanda a sé stante, forse su SO, ma la tua domanda ha già una risposta su Database Administrators.SE . In breve, anche un trigger "after update" viene eseguito prima del commit della transazione e se viene generata un'eccezione all'interno del trigger, si verificherà un rollback.
Doc Brown,

@GregBurghardt La maggior parte dei database contiene istruzioni che possono essere utilizzate per disabilitare i trigger per questo tipo di attività.
Blrfl,

1
@Blrfl: Sì, ma è necessario essere consapevoli del fatto che tali trigger potrebbero essere temporaneamente disabilitati per tutti gli utenti connessi, quando si desidera disabilitare solo condizionalmente i controlli per la sessione corrente.
Greg Burghardt,

Risposte:


12

Dipende dal tipo di sistema applicativo che stai costruendo:

  • se si sta creando un sistema incentrato sull'applicazione che contiene solo un'applicazione principale, con un database dedicato specifico per questa applicazione e idealmente un team responsabile dell'evoluzione fianco a fianco dell'applicazione e del database, è possibile mantenere tutta la logica di convalida e anche l'audit logica all'interno dell'applicazione.

    Il vantaggio principale di ciò è che non è necessario distribuire la logica di business tra applicazione e database, quindi mantenere ed evolvere il sistema diventa spesso più semplice. Come bonus, non si lega troppo l'applicazione a un tipo specifico di fornitore DBMS o DBMS. Questo approccio è ovviamente necessario se l'applicazione vuole essere in grado di utilizzare un sistema DB leggero che non fornisce trigger.

  • Se, tuttavia, si crea un sistema in cui molte applicazioni diverse condividono un database comune e non è possibile prevedere in anticipo quali applicazioni gli scriveranno in futuro o quali team svilupperanno applicazioni per il riempimento dei dati nel database in futuro, allora esso è meglio che il vostro database sarà responsabile di garantire la massima coerenza dei dati possibile. Ed è qui che i trigger diventano davvero utili. Nei sistemi più grandi, i vincoli referenziali spesso non sono sufficienti per questo, ma un trigger che chiama una procedura memorizzata può implementare quasi tutti i tipi di convalida necessari.

Un altro motivo per utilizzare i trigger può essere la prestazione: in modelli di dati complessi, non è raro incontrare regole di coerenza complesse che richiedono l'uso di molti dati aggiuntivi che non fanno parte del working set corrente disponibile nell'applicazione client. Il trasferimento di tutti questi dati sulla rete prima di rendere possibile la convalida sul lato client può avere un notevole impatto sulle prestazioni.

Vedi anche questo vecchio post di SE: Logica dell'applicazione Vs DB Trigger per la pulizia del database

Quindi decidi tu stesso che tipo di sistema stai costruendo, quindi puoi prendere una decisione fondata se i trigger sono lo strumento giusto per il tuo caso o meno.


3

Penso che la domanda riguardi la responsabilità della qualità dei dati.

La risposta dipende da come vedi il sistema.

Se vedi il database come un servizio indipendente, distinto e autonomo separato dall'applicazione, allora il database è responsabile di garantire la coerenza e la qualità dei dati che contiene. Essenzialmente perché quel database potrebbe essere utilizzato da un'applicazione diversa, quindi non può fare affidamento su quella seconda applicazione che ha la stessa coerenza e comportamenti di qualità. In queste circostanze, il database deve essere progettato per esporre un'API e un comportamento autonomo. In questa vista ci sono almeno due applicazioni, una è il database e l'altra è l'applicazione che lo utilizza.

Al contrario, il database potrebbe essere considerato una forma complicata di file che è sotto il controllo diretto e totale dell'applicazione. In questo senso il database si trasforma in un semplice strumento di serializzazione e navigazione dei documenti. Può fornire alcuni comportamenti avanzati per supportare le query e la manutenzione dei documenti (come fanno gli strumenti JSON o XML), ma non è necessario (come la maggior parte dei flussi di file). In questo caso è puramente responsabilità dei programmi mantenere il formato e il contenuto corretti all'interno del file. In questa vista esiste un'applicazione.

In entrambe le visualizzazioni, la domanda successiva è come supportare l'utilizzo del database come file di fantasia o come servizio separato. Puoi raggiungere questo obiettivo:

  • utilizzando gli strumenti che la piattaforma di database fornisce sotto forma di tabelle / viste / stored procedure / trigger / ecc ...
  • avvolgendo il database stesso all'interno di un servizio che tutti i client devono utilizzare per accedere al database
  • avvolgendo il database in una libreria che deve essere utilizzata da tutti i client per accedere ai dati.

Ognuno ha i suoi pro / contro e dipenderà dai vincoli architetturali dell'ambiente all'interno del quale il sistema opera.

Indipendentemente da quale vista si prenda, è sempre importante convalidare i dati ai confini.

  • Convalida i campi su un'interfaccia utente immessa da un utente
  • Convalida la richiesta di rete / API prima che lasci il client
  • Convalida la richiesta di rete / API nel server prima di fare qualsiasi cosa
  • Convalida i dati passati nelle regole aziendali
  • Convalida i dati prima di persistere
  • Convalida i dati dopo essere stati recuperati dalla persistenza
  • così via e così via

La quantità di convalida garantita su ciascun confine dipende da quanto sia rischioso non convalidarla.

  • moltiplicando due numeri insieme?
    • ottieni il numero sbagliato è un problema?
  • invocare una procedura in una determinata posizione di memoria?
    • Cosa c'è in quella posizione di memoria?
    • Cosa succede se l'oggetto non esiste o è in cattivo stato?
  • usando una regex su una stringa contenente kanji?
    • Il modulo regex può gestire unicode?
    • Il regex può gestire unicode?

La centralizzazione della logica di convalida è buona, ma i trigger imho non sono un buon modo per implementarla. Lavoravo su un sistema in cui più applicazioni condividevano tutte un database, con tutta la logica di validazione e gli effetti collaterali implementati nel database attraverso trigger e procedure memorizzate. Mi è venuta l'impressione che sia meglio avere un microservizio davanti al database e implementare tutta la logica lì. La logica non banale all'interno di un database SQL è un anti-pattern.
Joeri Sebrechts,

1
@JoeriSebrechts Ok, mi mordo: perché la logica non banale in un database è un antipattern, e cosa lo rende più un antipattern che metterlo in un programma gestito separatamente?
Blrfl,

@Blrfl Due motivi, l'API per accedere alla logica nel DB è inferiore a un'API del servizio Web (più difficile per la versione, più difficile da usare, non facilmente memorizzabile nella cache, ...) e i database rendono più difficile strutturare e mantenere in modo pulito il base di codice ospitata al loro interno. Nella mia esperienza, è più facile ospitare la logica in un servizio Web davanti al database piuttosto che all'interno di quel database.
Joeri Sebrechts,

@JoeriSebrechts Concordo sul fatto che la maggior parte delle piattaforme di database forniscono strumenti dolorosi per l'implementazione di un'API credibile, utile e sviluppabile. In molti modi è certamente un invito a provare molto dolore. Il mio punto era che si tratta di prospettiva, rendendosi conto che il DB è un file di fantasia, o che è veramente un servizio separato porta alla domanda successiva che è come avvolgerlo per supportare quello stile di utilizzo. Elaborerò la mia risposta per essere chiaro su questo.
Kain0_0

2

No, non devi mai usare i trigger per eseguire la convalida.

Il database è responsabile solo della propria integrità. Qualsiasi utente che si trova di fronte alla convalida deve essere eseguito dall'applicazione.

I database eseguono tre livelli di convalida per l'integrità. Il primo è la convalida a livello di campo. Un campo può essere richiesto, se non esiste alcun valore (null) è un errore. Può anche essere un vincolo di controllo; un dominio ha un numero enumerato di valori.

In secondo luogo ci sono relazioni tra le tabelle. In una tabella si memorizzano una o più chiavi esterne, correlando questa tabella ad altre tabelle e richiedendo che i valori siano chiavi valide per "l'altra tabella". Pensa a un database di indirizzi, in cui supportiamo indirizzi di diversi paesi. Una chiave di paese in un indirizzo deve puntare a un paese noto. Se i dati (ad esempio un codice postale) sono validi, non è un problema di questo controllo di integrità.

Terzo e più complicato sono i trigger. Come regola generale, questi dovrebbero riguardare (gioco di parole non inteso) le regole di integrità che sono condizionate. Per tornare all'esempio di indirizzo: se un paese non ha codici postali, sarebbe un problema se un paese in questo elenco avesse un codice postale. Quindi il controllo sarebbe: se questo paese non ha codici postali, il campo del codice postale dovrebbe essere nullo.

La convalida è la preoccupazione dell'applicazione. Il fatto che un codice postale tedesco sia composto da sole cifre è un controllo che l'applicazione dovrebbe effettuare, non il database. La linea è sottile, quindi potresti aver bisogno di pensare / discutere in alcuni casi se qualcosa dovrebbe essere in un trigger (proteggere l'integrità del tuo database) o nell'applicazione (convalida dell'utente).


Volevo solo aggiungere che se l'OP ha bisogno di aggiungere una regola di validazione acomplex che deve essere nel database, può sempre usare le procedure memorizzate come alternativa più sicura.
Borjab,

@Borjab: convalida come nel mantenere il database corretto, forse. Ma l'utente sta affrontando la convalida? No.
Menno Hölscher,

1
La tua prima affermazione dice "non usare mai i trigger per fare la validazione" , ma sotto scrivi "sì, puoi usare i trigger per certi tipi di validazione, e non è intrinsecamente chiaro dove tracciare la linea". Questo sembra abbastanza contraddittorio. Consiglierei di cancellare la tua prima frase, che migliorerebbe fortemente la tua risposta. Oh, e la tua ultima frase non risponde alla domanda di aggiornamento dei PO, poiché "prima / dopo" non ha nulla a che fare con la transazione. Consiglierei di eliminarlo pure. (vedi il mio commento sotto la domanda dei PO).
Doc Brown,

@DocBrown La distinzione è tra la protezione del database dalla corruzione e la convalida degli utenti. Quindi, in "qualsiasi ulteriore convalida", mi riferisco alla convalida per l'utente. Come potrei rendere più chiara questa distinzione? All'inizio ho rimosso "ulteriormente".
Menno Hölscher,

2
Va benissimo fare la validazione nel database. Proprio come va bene farlo nell'applicazione. Entrambi hanno i loro vantaggi. Fare la tua validazione nell'applicazione significa che devi fare molta attenzione ogni volta che esegui SQL senza il tuo ORM, necessario per quasi tutte le app complesse.
Qwertie,

1

L'audit è un classico esempio dell'uso efficace dei trigger. Ho riscontrato alcuni errori commessi dal tester (spostando un client da un livello di servizio all'altro) grazie a una tabella di audit che è stata implementata dai trigger. Consiglio vivamente di utilizzare i trigger per il controllo.

La convalida potrebbe essere fatta a livello di front-end, ma ho visto strani errori nel database che ho gestito (persone che sono nate nel 3000, ecc.), E poiché alcuni di loro mi sono fatto da solo, consiglio vivamente di avere un livello aggiuntivo di validazione nel database, per ogni evenienza. Naturalmente, questi tipi di errori potrebbero essere evitati con vincoli di controllo e molte volte sono più efficaci (in MS SQL sono il metodo preferito; controlla sempre la documentazione).


1

Perché la domanda è se abbiamo davvero bisogno di trigger per i database relazionali qui ci sono altri casi d'uso in cui usare i trigger:

  1. Per l'auditing come descritto nelle altre risposte.
  2. Controllo in senso lato: se una voce del database viene modificata, un trigger può registrare l'evento per la post-elaborazione asicrone, ad esempio le esportazioni notturne verso un'altra applicazione.
  3. Trigger per le visualizzazioni: è possibile definire i trigger instead of . In questo modo è possibile inserire, aggiornare ed eliminare voci da una vista. I trigger possono distribuire queste azioni su più tabelle. Questo è un modo per rendere disponibile una vista limitata senza esporre i dettagli delle tabelle sottostanti.
  4. Per salvare esplicitamente i turni di database: assumere una relazione N: M tra la tabella A e B e una tabella intermedia R. È possibile definire vincoli di chiave esterna da R a A e B specificando che la voce in R deve essere eliminata se si la voce corrispondente in B è cancellata. Tuttavia, a volte la logica aziendale richiede che le voci in A debbano avere almeno una relazione con una voce in B. In questo caso, un trigger all'eliminazione di R può aiutare a rafforzare questa logica: se per una voce in A l'ultima voce in R viene eliminato, quindi il trigger può eliminare A. Nella vista centrata dell'applicazione sono necessari almeno due giri. Questo è un esempio per la validazione. Sono possibili altri esempi: oltre ai casi d'uso (1), (2),
  5. Affidabilità: a volte gli amministratori del database modificano le voci sulla riga di comando che non utilizzano l'applicazione. Gli amministratori lavorano con attenzione e sanno cosa fanno. Tuttavia, a volte potrebbero essere sbagliati. Se la coerenza è fondamentale, un grilletto è la cintura di sicurezza.

Come svantaggio la logica aziendale è distribuita tra i livelli e questo è uno svantaggio principale per la manutenzione. Come ha scritto un altro autore, è un sottile confine tra applicazione e database e la scelta non è sempre chiara. La mia opinione personale è che i fattori scatenanti gravano sugli sviluppatori. Possono risparmiare tempo nello sviluppo. Sicuramente migliorano l'esperienza degli utenti perché aumentano le prestazioni su connessioni di rete lente.

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.