Guida rapida al caricamento dei dati iniziali con Spring Boot

1. Panoramica

Spring Boot rende davvero facile gestire le modifiche al nostro database in modo semplice. Se lasciamo la configurazione predefinita, cercherà le entità nei nostri pacchetti e creerà automaticamente le rispettive tabelle.

Ma a volte avremo bisogno di un controllo più dettagliato sulle alterazioni del database. È allora che possiamo usare i file data.sql e schema.sql in primavera.

2. Il file data.sql

Facciamo anche qui l'ipotesi che stiamo lavorando con JPA e definiamo una semplice entità Paese nel nostro progetto:

@Entity public class Country { @Id @GeneratedValue(strategy = IDENTITY) private Integer id; @Column(nullable = false) private String name; //... }

Se eseguiamo la nostra applicazione, Spring Boot creerà una tabella vuota per noi, ma non la popolerà con nulla.

Un modo semplice per farlo è creare un file denominato data.sql:

INSERT INTO country (name) VALUES ('India'); INSERT INTO country (name) VALUES ('Brazil'); INSERT INTO country (name) VALUES ('USA'); INSERT INTO country (name) VALUES ('Italy');

Quando eseguiamo il progetto con questo file sul classpath, Spring lo raccoglierà e lo utilizzerà per popolare il database.

3. Il file schema.sql

A volte, non vogliamo fare affidamento sul meccanismo di creazione dello schema predefinito. In questi casi, possiamo creare un file schema.sql personalizzato :

CREATE TABLE country ( id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR(128) NOT NULL, PRIMARY KEY (id) );

Spring raccoglierà questo file e lo utilizzerà per creare uno schema.

È anche importante ricordare di disattivare la creazione automatica dello schema per evitare conflitti:

spring.jpa.hibernate.ddl-auto=none

4. Controllo della creazione del database tramite Hibernate

Spring fornisce una proprietà specifica JPA che Hibernate utilizza per la generazione DDL: spring.jpa.hibernate.ddl-auto .

I valori delle proprietà Hibernate standard sono: create , update , create-drop , validate e none :

  • create - Hibernate prima elimina le tabelle esistenti, quindi crea nuove tabelle
  • update : il modello a oggetti creato in base alle mappature (annotazioni o XML) viene confrontato con lo schema esistente, quindi Hibernate aggiorna lo schema in base al diff. Non elimina mai le tabelle o le colonne esistenti anche se non sono più richieste dall'applicazione
  • create-drop - simile a create , con l'aggiunta che Hibernate eliminerà il database al termine di tutte le operazioni. Tipicamente utilizzato per unit test
  • validate - Hibernate convalida solo se le tabelle e le colonne esistono, altrimenti genera un'eccezione
  • nessuno : questo valore disattiva effettivamente la generazione DDL

Spring Boot imposta internamente questo valore di parametro su create-drop se non è stato rilevato alcun gestore di schemi, altrimenti nessuno per tutti gli altri casi.

Dobbiamo impostare il valore con attenzione o utilizzare uno degli altri meccanismi per inizializzare il database.

5. @Sql

Spring fornisce anche l' annotazione @Sql , un modo dichiarativo per inizializzare e popolare il nostro schema di test.

Vediamo come utilizzare l' annotazione @Sql per creare una nuova tabella e caricare anche la tabella con i dati iniziali per il nostro test di integrazione:

@Sql({"/employees_schema.sql", "/import_employees.sql"}) public class SpringBootInitialLoadIntegrationTest { @Autowired private EmployeeRepository employeeRepository; @Test public void testLoadDataForTestClass() { assertEquals(3, employeeRepository.findAll().size()); } }

Gli attributi dell'annotazione @Sql sono:

  • config - configurazione locale per gli script SQL. Lo descriviamo in dettaglio nella sezione successiva
  • executionPhase - possiamo anche specificare quando eseguire gli script, BEFORE_TEST_METHOD o AFTER_TEST_METHOD
  • istruzioni: possiamo dichiarare l'esecuzione di istruzioni SQL inline
  • scripts - possiamo dichiarare i percorsi ai file di script SQL da eseguire. Questo è un alias per l' attributo value

L' annotazione @Sql può essere utilizzata a livello di classe o di metodo . Possiamo caricare dati aggiuntivi richiesti per un particolare test case annotando quel metodo:

@Test @Sql({"/import_senior_employees.sql"}) public void testLoadDataForTestCase() { assertEquals(5, employeeRepository.findAll().size()); }
6. @SqlConfig

Possiamo configurare il modo in cui analizziamo ed eseguiamo gli script SQL utilizzando l' annotazione @SqlConfig .

@SqlConfig può essere dichiarato a livello di classe, dove funge da configurazione globale. Oppure può essere utilizzato per configurare una particolare annotazione @Sql .

Vediamo un esempio in cui specifichiamo la codifica dei nostri script SQL e la modalità di transazione per l'esecuzione degli script:

@Test @Sql(scripts = {"/import_senior_employees.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = TransactionMode.ISOLATED)) public void testLoadDataForTestCase() { assertEquals(5, employeeRepository.findAll().size()); }

E diamo un'occhiata ai vari attributi di @SqlConfig :

  • blockCommentStartDelimiter - delimitatore per identificare l'inizio dei commenti di blocco nei file di script SQL
  • blockCommentEndDelimiter - delimitatore per indicare la fine dei commenti di blocco nei file di script SQL
  • commentPrefix : prefisso per identificare i commenti su una sola riga nei file di script SQL
  • dataSource - nome del bean javax.sql.DataSource su cui verranno eseguiti gli script e le istruzioni
  • codifica : codifica per i file di script SQL, l'impostazione predefinita è la codifica della piattaforma
  • errorMode - modalità che verrà utilizzata quando si verifica un errore durante l'esecuzione degli script
  • separatore - stringa utilizzata per separare singole istruzioni, il valore predefinito è "-"
  • transactionManager : nome del bean di PlatformTransactionManager che verrà utilizzato per le transazioni
  • transactionMode : la modalità che verrà utilizzata durante l'esecuzione degli script nella transazione

7. @SqlGroup

Java 8 and above allow the use of repeated annotations. This feature can be utilized for @Sql annotations as well. For Java 7 and below, there is a container annotation — @SqlGroup. Using the @SqlGroup annotation, we can declare multiple @Sql annotations:

@SqlGroup({ @Sql(scripts = "/employees_schema.sql", config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)), @Sql("/import_employees.sql")}) public class SpringBootSqlGroupAnnotationIntegrationTest { @Autowired private EmployeeRepository employeeRepository; @Test public void testLoadDataForTestCase() { assertEquals(3, employeeRepository.findAll().size()); } }

8. Conclusion

In this quick article, we saw how we can leverage schema.sql and data.sql files for setting up an initial schema and populating it with data. We also saw how we can use @Sql, @SqlConfig, and @SqlGroup annotations to load test data for tests.

Tieni presente che questo approccio è più adatto per scenari di base e semplici, qualsiasi gestione avanzata del database richiederebbe strumenti più avanzati e raffinati come Liquibase o Flyway.

Gli snippet di codice, come sempre, possono essere trovati su GitHub.