Va bene eseguire le applicazioni Hibernate configurate hbm2ddl.auto=update
per aggiornare lo schema del database in un ambiente di produzione?
Va bene eseguire le applicazioni Hibernate configurate hbm2ddl.auto=update
per aggiornare lo schema del database in un ambiente di produzione?
Risposte:
No, non è sicuro.
Nonostante i migliori sforzi del team Hibernate, semplicemente non puoi fare affidamento sugli aggiornamenti automatici in produzione . Scrivi le tue patch, esaminale con DBA, testale, quindi applicale manualmente.
Teoricamente, se l'aggiornamento di hbm2ddl ha funzionato nello sviluppo, dovrebbe funzionare anche nella produzione. Ma in realtà non è sempre così.
Anche se ha funzionato bene, potrebbe non essere ottimale. I DBA vengono pagati così tanto per un motivo.
Lo facciamo in produzione anche se con un'applicazione non mission-critical e senza DBA altamente retribuiti per il personale. È solo un processo manuale in meno soggetto a errore umano: l'applicazione è in grado di rilevare la differenza e fare la cosa giusta, inoltre presumibilmente l'hai testata in vari ambienti di sviluppo e test.
Un avvertimento: in un ambiente cluster potresti volerlo evitare perché più app possono venire contemporaneamente e provare a modificare lo schema che potrebbe essere negativo. O inserire un meccanismo in cui solo un'istanza è autorizzata ad aggiornare lo schema.
I creatori di Hibernate scoraggiano farlo in un ambiente di produzione nel loro libro "Java Persistence with Hibernate" :
ATTENZIONE: abbiamo visto gli utenti di Hibernate tentare di utilizzare SchemaUpdate per aggiornare automaticamente lo schema di un database di produzione. Questo può rapidamente finire in un disastro e non sarà consentito dal tuo DBA.
Dai un'occhiata a LiquiBase XML per tenere un registro degli aggiornamenti. Non l'avevo mai usato fino a quest'anno, ma ho scoperto che è molto facile da imparare e rendere il controllo delle revisioni DB / migrazione / gestione delle modifiche molto infallibile. Lavoro a un progetto Groovy / Grails e Grails usa Hibernate per tutto il suo ORM (chiamato "GORM"). Utilizziamo Liquibase per gestire tutte le modifiche allo schema SQL, cosa che facciamo abbastanza spesso man mano che la nostra app si evolve con nuove funzionalità.
Fondamentalmente, mantieni un file XML di changeset che continui ad aggiungere man mano che la tua applicazione si evolve. Questo file è tenuto in git (o qualunque cosa tu stia usando) con il resto del tuo progetto. Quando la tua app viene distribuita, Liquibase controlla la sua tabella dei log nel DB a cui ti stai connettendo in modo che sappia cosa è già stato applicato, quindi applica in modo intelligente qualsiasi modifica che non sia stata ancora applicata dal file. In pratica funziona alla grande e, se lo usi per tutte le modifiche allo schema, puoi essere sicuro al 100% che il codice che esegui il checkout e la distribuzione sarà sempre in grado di connettersi a uno schema di database completamente compatibile.
La cosa fantastica è che posso prendere un database mysql di ardesia totalmente vuoto sul mio laptop, avviare l'app e subito lo schema è impostato per me. Inoltre, semplifica il test delle modifiche allo schema applicandole prima a un sviluppatore locale o alla gestione temporanea del db.
Il modo più semplice per iniziare sarebbe probabilmente quello di prendere il tuo DB esistente e quindi utilizzare Liquibase per generare un file iniziale baseline.xml. Quindi in futuro puoi semplicemente aggiungerlo e lasciare che la liquibase prenda il controllo della gestione delle modifiche dello schema.
hbm2ddl.auto=update
modo che i tuoi mapping Class / DB siano validati e tu abbia il controllo completo della creazione di DB attraverso liquibase. Cosa ne pensi?
validate
Vorrei votare no. Hibernate non sembra capire quando i tipi di dati per le colonne sono cambiati. Esempi (usando MySQL):
String with @Column(length=50) ==> varchar(50)
changed to
String with @Column(length=100) ==> still varchar(50), not changed to varchar(100)
@Temporal(TemporalType.TIMESTAMP,TIME,DATE) will not update the DB columns if changed
Probabilmente ci sono anche altri esempi, come spingere la lunghezza di una colonna String su 255 e vederla convertire in testo, testo medio, ecc. Ecc.
Certo, non credo che ci sia davvero un modo per "convertire i tipi di dati" senza creare una nuova colonna, copiare i dati e spazzare via la vecchia colonna. Ma nel momento in cui il tuo database ha colonne che non riflettono l'attuale mappatura di Hibernate, stai vivendo molto pericolosamente ...
Flyway è una buona opzione per affrontare questo problema:
@Column(length = 45)
in @Column(length = 255)
. Può verificare che Hibernate 4.3.6.Final abbia aggiornato correttamente lo schema del database usando hbm2ddl.auto=update
. (Una cosa da menzionare è che al momento il database non contiene alcun dato - solo la struttura.)
Hibernate deve mettere il disclaimer sul non usare gli aggiornamenti automatici in prod per coprirsi quando le persone che non sanno cosa stanno facendo lo usano in situazioni in cui non dovrebbe essere usato.
Concesso le situazioni in cui non dovrebbe essere usato molto più di quelle in cui è OK.
L'ho usato per anni in molti progetti diversi e non ho mai avuto un singolo problema. Non è una risposta scadente e non è la codifica da cowboy. È un fatto storico.
Una persona che dice "non farlo mai in produzione" sta pensando a un insieme specifico di schieramenti di produzione, vale a dire quelli con cui ha familiarità (la sua azienda, la sua industria, ecc.).
L'universo delle "distribuzioni di produzione" è vasto e vario.
Uno sviluppatore Hibernate con esperienza sa esattamente quale sarà il risultato DDL da una determinata configurazione di mappatura. Finché testate e confermate che ciò che vi aspettate finisce nel DDL (in sviluppo, qa, messa in scena, ecc.), State bene.
Quando aggiungi molte funzionalità, gli aggiornamenti automatici dello schema possono farti risparmiare tempo reale.
L'elenco di cose che gli aggiornamenti automatici non gestiranno è infinito, ma alcuni esempi sono la migrazione dei dati, l'aggiunta di colonne non annullabili, le modifiche dei nomi delle colonne, ecc. Ecc.
Inoltre, è necessario prestare attenzione in ambienti cluster.
Ma poi di nuovo, se conoscessi tutta questa roba, non faresti questa domanda. Hmm . . OK, se stai ponendo questa domanda, dovresti aspettare fino a quando non avrai molta esperienza con Hibernate e gli aggiornamenti dello schema automatico prima di pensare di usarlo in prod.
Come ho spiegato in questo articolo , non è una buona idea usare hbm2ddl.auto
in produzione.
L'unico modo per gestire lo schema del database è utilizzare gli script di migrazione incrementale perché:
Anche la Guida dell'utente di Hibernate ti consiglia di evitare di utilizzare lo hbm2ddl
strumento per ambienti di produzione.
SchemaExport
come dimostrato da questo caso di test .
Lo facciamo in un progetto in esecuzione da mesi ormai e non abbiamo mai avuto problemi finora. Tieni presente i 2 ingredienti necessari per questa ricetta:
Progetta il tuo modello a oggetti con un approccio di retrocompatibilità, ovvero deprecare oggetti e attributi anziché rimuoverli / alterarli. Ciò significa che se è necessario modificare il nome di un oggetto o di un attributo, lasciare quello vecchio così com'è, aggiungere quello nuovo e scrivere una sorta di script di migrazione. Se hai bisogno di cambiare un'associazione tra oggetti, se sei già in produzione, questo significa che il tuo design era in primo luogo sbagliato, quindi prova a pensare a un nuovo modo di esprimere la nuova relazione, senza influire sui vecchi dati.
Eseguire sempre il backup del database prima della distribuzione.
Il mio senso è - dopo aver letto questo post - che il 90% delle persone che prendono parte a questa discussione sono inorriditi solo dal pensiero di usare automazioni come questa in un ambiente di produzione. Alcuni lanciano la palla al DBA. Prenditi un momento per considerare che non tutti gli ambienti di produzione forniranno un DBA e non molti team di sviluppatori sono in grado di permettersene uno (almeno per progetti di medie dimensioni). Quindi, se stiamo parlando di squadre in cui tutti devono fare tutto, la palla è su di loro.
In questo caso, perché non provare ad avere il meglio dei due mondi? Strumenti come questo sono qui per dare una mano, che - con una progettazione e un piano accurati - può aiutare in molte situazioni. E credetemi, inizialmente gli amministratori potrebbero essere difficili da convincere, ma se sanno che la palla non è nelle loro mani, lo adoreranno.
Personalmente, non tornerei mai più a scrivere script a mano per estendere qualsiasi tipo di schema, ma questa è solo la mia opinione. E dopo aver iniziato ad adottare database NoSQL senza schema di recente, posso vedere che più che presto, tutte queste operazioni basate su schemi apparterranno al passato, quindi è meglio iniziare a cambiare prospettiva e guardare avanti.
Non rischierei perché potresti perdere dati che avrebbero dovuto essere conservati. hbm2ddl.auto = update è puramente un modo semplice per mantenere aggiornato il database degli sviluppatori.
Nel mio caso (Hibernate 3.5.2, Postgresql, Ubuntu), impostazione hibernate.hbm2ddl.auto=update
creato solo nuove tabelle e creato nuove colonne in tabelle già esistenti.
Non ha lasciato cadere le tabelle, né le colonne, né le colonne modificate. Può essere definita un'opzione sicura, ma qualcosa di simile hibernate.hbm2ddl.auto=create_tables add_columns
sarebbe più chiaro.
Non è sicuro, non raccomandato, ma è possibile.
Ho esperienza in un'applicazione che utilizza l'opzione di aggiornamento automatico in produzione.
Bene, i principali problemi e rischi riscontrati in questa soluzione sono:
Quindi, non consiglierò di utilizzare l'aggiornamento automatico in produzione.
Se vuoi davvero utilizzare l'aggiornamento automatico in produzione, ti consiglio di:
E, a differenza degli altri post, non credo che l'aggiornamento automatico abbia consentito che sia correlato a DBA "molto ben pagati" (come menzionato in altri post). I DBA hanno cose più importanti da fare che scrivere istruzioni SQL per creare / modificare / eliminare tabelle e colonne. Queste semplici attività quotidiane possono essere eseguite e automatizzate dagli sviluppatori e passate solo al team DBA per la revisione, senza che Hibernate e DBA siano "molto ben pagati" per scriverle.
In genere, le applicazioni aziendali in organizzazioni di grandi dimensioni vengono eseguite con privilegi ridotti.
Il nome utente del database potrebbe non avere il DDL
privilegio di aggiungere colonne che hbm2ddl.auto=update
richiede.
Sono d'accordo con Vladimir. Gli amministratori della mia azienda non apprezzerebbero sicuramente se avessi anche suggerito un simile corso.
Inoltre, la creazione di uno script SQL al posto della fiducia cieca di Hibernate ti dà la possibilità di rimuovere i campi che non sono più in uso. Ibernazione non lo fa.
E trovo che il confronto dello schema di produzione con il nuovo schema ti offra una visione ancora migliore di ciò che hai cambiato nel modello di dati. Sai, ovviamente, perché ce l'hai fatta, ma ora vedi tutti i cambiamenti in una volta sola. Anche quelli che ti fanno andare come "Che diamine ?!".
Ci sono strumenti che possono creare un delta dello schema per te, quindi non è nemmeno un duro lavoro. E poi sai esattamente cosa succederà.
Lo schema delle applicazioni potrebbe evolversi nel tempo; se si dispone di più installazioni, che possono trovarsi in versioni diverse, è necessario disporre di un modo per garantire che l'applicazione, un qualche tipo di strumento o script sia in grado di migrare schemi e dati da una versione in modo graduale a una successiva.
Avere tutta la tua persistenza nelle mappature (o annotazioni) di Hibernate è un ottimo modo per tenere sotto controllo l'evoluzione dello schema.
Dovresti considerare che l'evoluzione dello schema ha diversi aspetti da considerare:
evoluzione dello schema del database nell'aggiunta di più colonne e tabelle
caduta di vecchie colonne, tabelle e relazioni
riempire nuove colonne con valori predefiniti
Gli strumenti di ibernazione sono importanti in particolare nel caso (come nella mia esperienza) hai versioni diverse della stessa applicazione su molti tipi diversi di database.
Il punto 3 è molto sensibile nel caso in cui si utilizzi Hibernate, come nel caso in cui si introduca una nuova proprietà booleana valutata o numerica, se Hibernate troverà un valore nullo in tali colonne, se solleverà un'eccezione.
Quindi quello che vorrei fare è: utilizzare davvero la capacità degli strumenti di Hibernate di aggiornamento dello schema, ma è necessario aggiungere al suo fianco alcuni callback di manutenzione dei dati e dello schema, come per riempire i valori predefiniti, eliminare colonne non più utilizzate e simili. In questo modo si ottengono i vantaggi (script di aggiornamento dello schema indipendenti dal database ed evitando la duplicazione della codifica degli aggiornamenti, in peristenza e negli script) ma si coprono anche tutti gli aspetti dell'operazione.
Quindi, ad esempio, se un aggiornamento di versione consiste semplicemente nell'aggiunta di una proprietà con valore varchar (quindi colonna), che può essere impostata su null per impostazione predefinita, con l'aggiornamento automatico verrà eseguito. Laddove è necessaria una maggiore complessità, sarà necessario più lavoro.
Ciò presuppone che l'applicazione, una volta aggiornata, sia in grado di aggiornare il suo schema (è possibile farlo), il che significa anche che deve disporre dei diritti utente per farlo sullo schema. Se la politica del cliente lo impedisce (probabile caso Lizard Brain), dovrai fornire gli script specifici del database.