Guía rápida sobre la carga de datos iniciales con Spring Boot

1. Información general

Spring Boot hace que sea realmente fácil administrar los cambios de nuestra base de datos de una manera sencilla. Si dejamos la configuración predeterminada, buscará entidades en nuestros paquetes y creará las tablas respectivas automáticamente.

Pero a veces necesitaremos un control más detallado sobre las alteraciones de la base de datos. Ahí es cuando podemos usar los archivos data.sql y schema.sql en Spring.

2. El archivo data.sql

Supongamos también aquí que estamos trabajando con JPA y definamos una entidad Country simple en nuestro proyecto:

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

Si ejecutamos nuestra aplicación, Spring Boot creará una tabla vacía para nosotros, pero no la completará con nada.

Una forma fácil de hacer esto es crear un archivo llamado 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');

Cuando ejecutamos el proyecto con este archivo en la ruta de clases, Spring lo recogerá y lo usará para completar la base de datos.

3. El archivo schema.sql

A veces, no queremos depender del mecanismo de creación de esquemas predeterminado. En tales casos, podemos crear un archivo schema.sql personalizado :

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

Spring tomará este archivo y lo usará para crear un esquema.

También es importante recordar desactivar la creación automática de esquemas para evitar conflictos:

spring.jpa.hibernate.ddl-auto=none

4. Control de la creación de bases de datos mediante Hibernate

Spring proporciona una propiedad específica de JPA que Hibernate usa para la generación de DDL: spring.jpa.hibernate.ddl-auto .

Los valores de propiedad estándar de Hibernate son: crear , actualizar , crear-soltar , validar y ninguno :

  • crear : Hibernate primero elimina las tablas existentes y luego crea nuevas tablas
  • actualizar : el modelo de objeto creado en base a las asignaciones (anotaciones o XML) se compara con el esquema existente, y luego Hibernate actualiza el esquema de acuerdo con las diferencias. Nunca elimina las tablas o columnas existentes, incluso si la aplicación ya no las requiere
  • create-drop - similar a create , con la adición de que Hibernate eliminará la base de datos después de que se completen todas las operaciones. Normalmente se utiliza para pruebas unitarias
  • validar : Hibernate solo valida si las tablas y columnas existen; de lo contrario, arroja una excepción
  • ninguno : este valor apaga efectivamente la generación DDL

Spring Boot establece internamente el valor predeterminado de este parámetro en create-drop si no se ha detectado ningún administrador de esquema, de lo contrario, ninguno para todos los demás casos.

Tenemos que establecer el valor con cuidado o usar uno de los otros mecanismos para inicializar la base de datos.

5. @Sql

Spring también proporciona la anotación @Sql , una forma declarativa de inicializar y completar nuestro esquema de prueba.

Veamos cómo usar la anotación @Sql para crear una nueva tabla y también cargar la tabla con los datos iniciales para nuestra prueba de integración:

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

Los atributos de la anotación @Sql son:

  • config: configuración local para los scripts SQL. Describimos esto en detalle en la siguiente sección.
  • executionPhase: también podemos especificar cuándo ejecutar los scripts, ya sea BEFORE_TEST_METHOD o AFTER_TEST_METHOD
  • declaraciones: podemos declarar declaraciones SQL en línea para ejecutar
  • scripts: podemos declarar las rutas a los archivos de script SQL para ejecutar. Este es un alias para el atributo de valor.

La anotación @Sql se puede utilizar a nivel de clase o de método . Podemos cargar datos adicionales necesarios para un caso de prueba en particular anotando ese método:

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

Podemos configurar la forma en que analizamos y ejecutamos los scripts SQL usando la anotación @SqlConfig .

@SqlConfig se puede declarar a nivel de clase, donde sirve como configuración global. O se puede utilizar para configurar una anotación @Sql particular .

Veamos un ejemplo en el que especificamos la codificación de nuestros scripts SQL, así como el modo de transacción para ejecutar los scripts:

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

Y veamos los diversos atributos de @SqlConfig :

  • blockCommentStartDelimiter : delimitador para identificar el inicio de los comentarios de bloque en archivos de script SQL
  • blockCommentEndDelimiter : delimitador para indicar el final de los comentarios del bloque en archivos de script SQL
  • commentPrefix - prefijo para identificar comentarios de una sola línea en archivos de script SQL
  • dataSource : nombre del bean javax.sql.DataSource contra el que se ejecutarán los scripts y las sentencias
  • codificación : codificación para los archivos de script SQL, el valor predeterminado es la codificación de plataforma
  • errorMode : modo que se utilizará cuando se encuentre un error al ejecutar los scripts
  • separador : cadena utilizada para separar declaraciones individuales, el valor predeterminado es "-"
  • transactionManager : nombre de bean del PlatformTransactionManager que se utilizará para las transacciones
  • transactionMode : el modo que se utilizará al ejecutar scripts en una transacción

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.

Tenga en cuenta que este enfoque es más adecuado para escenarios básicos y simples, cualquier manejo avanzado de bases de datos requeriría herramientas más avanzadas y refinadas como Liquibase o Flyway.

Los fragmentos de código, como siempre, se pueden encontrar en GitHub.