Перейти к основному содержимому

Краткое руководство по загрузке исходных данных с помощью Spring Boot

· 6 мин. чтения

1. Обзор

Spring Boot позволяет очень легко управлять изменениями в нашей базе данных. Если мы оставим конфигурацию по умолчанию, она будет искать сущности в наших пакетах и автоматически создавать соответствующие таблицы.

Но иногда нам потребуется более тонкий контроль над изменениями в базе данных. И тогда мы можем использовать файлы data.sql и schema.sql в Spring.

2. Файл data.sql

Давайте также предположим, что мы работаем с JPA, и определим простую сущность Country в нашем проекте:

@Entity
public class Country {

@Id
@GeneratedValue(strategy = IDENTITY)
private Integer id;

@Column(nullable = false)
private String name;

//...
}

Если мы запустим наше приложение, Spring Boot создаст для нас пустую таблицу, но ничем ее не заполнит.

Простой способ сделать это — создать файл с именем 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');

Когда мы запустим проект с этим файлом в пути к классам, Spring подберет его и будет использовать для заполнения базы данных.

3. Файл schema.sql

Иногда мы не хотим полагаться на механизм создания схемы по умолчанию.

В таких случаях мы можем создать собственный файл schema.sql :

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

Spring возьмет этот файл и будет использовать его для создания схемы.

Обратите внимание, что инициализация на основе сценариев, т. е. через schema.sql и data.sql, и инициализация Hibernate вместе могут вызвать некоторые проблемы.

Либо отключаем автоматическое создание схемы Hibernate:

spring.jpa.hibernate.ddl-auto=none

Это гарантирует, что инициализация на основе сценария выполняется напрямую с использованием schema.sql и data.sql .

Если мы по-прежнему хотим иметь автоматическую генерацию схемы Hibernate в сочетании с созданием схемы на основе сценариев и заполнением данных, нам придется использовать:

spring.jpa.defer-datasource-initialization=true

Это гарантирует, что после создания схемы Hibernate дополнительно считывается schema.sql для любых дополнительных изменений схемы, а data.sql выполняется для заполнения базы данных.

Кроме того, инициализация на основе сценариев выполняется по умолчанию только для встроенных баз данных, чтобы всегда инициализировать базу данных с помощью сценариев, нам придется использовать:

spring.sql.init.mode=always

Пожалуйста, обратитесь к официальной документации Spring по инициализации баз данных с помощью сценариев SQL .

4. Управление созданием базы данных с помощью Hibernate

Spring предоставляет специфичное для JPA свойство, которое Hibernate использует для генерации DDL: spring.jpa.hibernate.ddl-auto .

Стандартными значениями свойств Hibernate являются create , update , create-drop , validate и none :

  • create — Hibernate сначала удаляет существующие таблицы, а затем создает новые.
  • update — объектная модель, созданная на основе отображений (аннотаций или XML), сравнивается с существующей схемой, а затем Hibernate обновляет схему в соответствии с diff. Он никогда не удаляет существующие таблицы или столбцы, даже если они больше не требуются приложению.
  • create-drop — аналогично create , с той лишь разницей, что Hibernate удалит базу данных после завершения всех операций; обычно используется для модульного тестирования
  • validate — Hibernate проверяет только существование таблиц и столбцов; в противном случае выдается исключение.
  • none — это значение эффективно отключает генерацию DDL.

Spring Boot по умолчанию устанавливает для этого параметра значение create-drop , если менеджер схемы не обнаружен, в противном случае — ни для всех остальных случаев.

Мы должны тщательно установить значение или использовать один из других механизмов для инициализации базы данных.

5. Настройка создания схемы базы данных

По умолчанию Spring Boot автоматически создает схему встроенного источника данных .

Если нам нужно контролировать или настраивать это поведение, мы можем использовать свойство spring.sql.init.mode . Это свойство принимает одно из трех значений:

  • всегда — всегда инициализировать базу данных
  • встроенный — всегда инициализируйте, если используется встроенная база данных. Это значение по умолчанию, если значение свойства не указано.
  • никогда — никогда не инициализировать базу данных

Примечательно, что если мы используем невстроенную базу данных, скажем, MySQL или PostGreSQL, и хотим инициализировать ее схему, нам нужно установить для этого свойства значение always .

Это свойство было введено в Spring Boot 2.5.0; нам нужно использовать spring.datasource.initialization-mode , если мы используем предыдущие версии Spring Boot.

6. @SQL

Spring также предоставляет аннотацию @Sql — декларативный способ инициализации и заполнения нашей тестовой схемы.

Давайте посмотрим, как использовать аннотацию @Sql для создания новой таблицы, а также загрузить таблицу с исходными данными для нашего интеграционного теста:

@Sql({"/employees_schema.sql", "/import_employees.sql"})
public class SpringBootInitialLoadIntegrationTest {

@Autowired
private EmployeeRepository employeeRepository;

@Test
public void testLoadDataForTestClass() {
assertEquals(3, employeeRepository.findAll().size());
}
}

Вот атрибуты аннотации @Sql :

  • config — локальная конфигурация для скриптов SQL. Мы подробно опишем это в следующем разделе.
  • executePhase — мы также можем указать, когда выполнять скрипты, либо BEFORE_TEST_METHOD , либо AFTER_TEST_METHOD .
  • операторы — мы можем объявить встроенные операторы SQL для выполнения.
  • сценарии — мы можем объявить пути к файлам сценариев SQL для выполнения. Это псевдоним атрибута value .

Аннотация @Sql может использоваться на уровне класса или на уровне метода.

Мы загрузим дополнительные данные, необходимые для конкретного теста, аннотировав этот метод:

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

7. @SqlConfig

Мы можем настроить способ анализа и запуска сценариев SQL с помощью аннотации @SqlConfig .

@SqlConfig можно объявить на уровне класса, где он служит глобальной конфигурацией. Или мы можем использовать его для настройки конкретной аннотации @Sql .

Давайте посмотрим на пример, где мы указываем кодировку наших скриптов SQL, а также режим транзакций для выполнения скриптов:

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

И давайте посмотрим на различные атрибуты @SqlConfig :

  • blockCommentStartDelimiter — разделитель для обозначения начала комментариев блока в файлах сценариев SQL.
  • blockCommentEndDelimiter — разделитель для обозначения конца комментариев к блоку в файлах сценариев SQL.
  • commentPrefix — префикс для идентификации однострочных комментариев в файлах сценариев SQL .
  • dataSource — имя bean-компонента javax.sql.DataSource , для которого будут выполняться сценарии и операторы.
  • encoding – кодировка для файлов скриптов SQL; по умолчанию используется кодировка платформы
  • errorMode — режим, который будет использоваться при возникновении ошибки при запуске скриптов.
  • separator – строка, используемая для разделения отдельных операторов; по умолчанию "-"
  • transactionManager — имя bean-компонента PlatformTransactionManager , который будет использоваться для транзакций .
  • transactionMode — режим, который будет использоваться при выполнении скриптов в транзакции

8. @SqlGroup

Java 8 и выше позволяют использовать повторяющиеся аннотации. Мы также можем использовать эту функцию для аннотаций @Sql . Для Java 7 и ниже есть аннотация контейнера — @SqlGroup .

Используя аннотацию @SqlGroup , мы объявим несколько аннотаций @Sql :

@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());
}
}

9. Заключение

В этой быстрой статье мы увидели, как мы можем использовать файлы schema.sql и data.sql для настройки исходной схемы и заполнения ее данными.

Мы также рассмотрели, как использовать аннотации @Sql , @SqlConfig и @SqlGroup для загрузки тестовых данных для тестов.

Имейте в виду, что этот подход больше подходит для базовых и простых сценариев, и для любой расширенной обработки базы данных потребуются более продвинутые и совершенные инструменты, такие как Liquibase или Flyway .

Фрагменты кода, как всегда, можно найти на GitHub .