Пакет org.springframework.jdbc.datasource.embedded забезпечує підтримку вбудованих підсистем зберігання на Java. Підтримка HSQL, H2 та Derby забезпечується нативно. Також можна використовувати розширюваний API-інтерфейс для підключення нових вбудованих типів баз даних та реалізацій DataSource.

Навіщо використовувати вбудовану базу даних?

Вбудована база даних може бути корисна на етапі розробки проєкту завдяки своїй спрощеності. Серед переваг — простота налаштування, швидкий час запуску, тестованість і можливість швидкого доопрацювання SQL у процесі розробки.

Створення вбудованої бази даних за допомогою Spring XML

Якщо вам потрібно подати екземпляр вбудованої бази даних як бін у ApplicationContext у Spring, можна використовувати тег embedded-database у просторі імен spring-jdbc:


<jdbc:embedded-database id="dataSource" generate-name ="true">
    <jdbc:script location="classpath:schema.sql"/>
    <jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>

Попередня конфігурація створює вбудовану базу даних HSQL, яка заповнюється SQL з ресурсів schema.sql і test-data.sql в корені classpath. До того ж, як оптимальний метод роботи вбудованій базі даних дається унікальне ім'я. Вбудована база даних стає доступною для контейнера Spring як бін типу javax.sql.DataSource, який потім можна впроваджувати до об'єктів доступу до даних у разі необхідності.

Створення вбудованої бази даних програмним способом

Клас EmbeddedDatabaseBuilder надає вільний API-інтерфейс для створення вбудованої бази даних програмним шляхом. Це можна використовувати, якщо потрібно створити вбудовану базу даних в автономному оточенні або в автономному інтеграційному тесті, як у наступному прикладі:

Java

EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
        .generateUniqueName(true)
        .setType(H2)
        .setScriptEncoding("UTF-8")
        .ignoreFailedDrops(true)
        .addScript("schema.sql")
        .addScripts("user_data.sql", "country_data.sql")
        .build();
// виконуємо дії з базою даних (EmbeddedDatabase розширює javax.sql.DataSource) db.shutdown()
db.shutdown()
Kotlin

val db = EmbeddedDatabaseBuilder()
        .generateUniqueName(true)
        .setType(H2)
        .setScriptEncoding("UTF-8")
        .ignoreFailedDrops(true)
        .addScript("schema.sql")
        .addScripts("user_data.sql", "country_data.sql")
        .build()
// виконуємо дії з базою даних (EmbeddedDatabase розширює javax.sql.DataSource)
db.shutdown()

Див. javadoc EmbeddedDatabaseBuilder для отримання більш детальної інформації про всі опції, що підтримуються.

Також можна використовувати EmbeddedDatabaseBuilder для створення вбудованої бази даних за допомогою конфігурації Java, як показано в наступному прикладі:

Java

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .generateUniqueName(true)
                .setType(H2)
                .setScriptEncoding("UTF-8")
                .ignoreFailedDrops(true)
                .addScript("schema.sql")
                .addScripts("user_data.sql", "country_data.sql")
                .build();
    }
}
Kotlin

@Configuration
class DataSourceConfig {
    @Bean
    fun dataSource(): DataSource {
        return EmbeddedDatabaseBuilder()
                .generateUniqueName(true)
                .setType(H2)
                .setScriptEncoding("UTF-8")
                .ignoreFailedDrops(true)
                .addScript("schema.sql")
                .addScripts("user_data.sql", "country_data.sql")
                .build()
    }
}

Вибір типу вбудованої бази даних

У цьому розділі розповідається про те, як обрати одну з трьох вбудованих баз даних, що підтримує Spring. Розділ включає наступні теми:

  • Використання HSQL

  • Використання H2

  • Використання Derby

Використання HSQL

Spring підтримує HSQL 1.8.0 і вище. HSQL є вбудованою базою даних за замовчуванням, якщо тип не зазначений явно. Щоб явно встановити HSQL, встанови для атрибуту type тега embedded-database значення HSQL. Якщо ти використовуєш API-інтерфейс системи збірки, виклич метод setType(EmbeddedDatabaseType) з параметром EmbeddedDatabaseType.HSQL.

Використання H2

Spring підтримує базу даних H2. Щоб активувати H2, встанови для атрибуту type тега embedded-database значення H2. Якщо ти використовуєш API-інтерфейс засобу збирання, виклич метод setType(EmbeddedDatabaseType) із параметром EmbeddedDatabaseType.H2.

Використання Derby

Spring підтримує Apache Derby 10.5 і вище. Щоб активувати Derby, встанови для атрибуту type тега embedded-database значення DERBY. Якщо ти використовуєш API-інтерфейс засобу збирання, виклич метод setType(EmbeddedDatabaseType) із параметром EmbeddedDatabaseType.DERBY.

Тестування логіки доступу до даних із використанням вбудованої бази даних

Вбудовані бази даних забезпечують легкий спосіб тестування коду для отримання вибірки даних. Наступний приклад — шаблон інтеграційного тесту доступу до даних, у якому використовується вбудована база даних. Використання такого шаблону може бути корисним для разових випадків, якщо вбудовану базу даних не потрібно повторно використовувати у всіх тестових класах. Однак, якщо потрібно створити вбудовану базу даних, яка буде використовуватися спільно в тестовому комплекті, використовуй Spring TestContext Framework та налаштуй вбудовану базу даних як бін у ApplicationContext з Spring, як це описано вище. У наступному лістингу показаний тестовий шаблон:

Java

public class DataAccessIntegrationTestTemplate {
    private EmbeddedDatabase db;
    @BeforeEach
    public void setUp() {
        // створює резидентну (зі зберіганням в оперативній пам'яті) базу даних HSQL, заповнену стандартними скриптами
        // classpath:schema.sql і classpath:data.sql
        db = new EmbeddedDatabaseBuilder()
                .generateUniqueName(true )
                .addDefaultScripts()
                .build();
    }
    @Test
    public void testDataAccess() {
        JdbcTemplate template = new JdbcTemplate(db);
        template.query( /* ... */ );
    }
    @AfterEach
    public void tearDown() {
        db.shutdown();
    }
}
Kotlin
class DataAccessIntegrationTestTemplate {
    private lateinit var db: EmbeddedDatabase
    @BeforeEach
    fun setUp() {
        // створює резидентну (зі зберіганням в оперативній пам'яті) базу даних HSQL, заповнену стандартними скриптами
        // classpath:schema.sql and classpath:data.sql
        db = EmbeddedDatabaseBuilder()
                .generateUniqueName(true)
                .addDefaultScripts()
                .build()
    }
    @Test
    fun testDataAccess() {
        val template = JdbcTemplate(db)
        template.query( /* ... */)
    }
    @AfterEach
    fun tearDown() {
        db.shutdown()
    }
}

Створення унікальних імен для вбудованих баз даних

Команди розробників часто стикаються з помилками під час роботи з вбудованими базами даних, якщо їх тестовий комплект випадково намагається відтворити додаткові екземпляри однієї і тієї ж бази даних. Це досить легко може статися, якщо файл конфігурації XML або клас з анотацією @Configuration відповідає за створення вбудованої бази даних, а відповідна конфігурація потім повторно використовується в кількох сценаріях тестування в межах одного тестового комплекту (тобто в рамках одного процесу JVM) — наприклад, інтеграційні тести щодо вбудованих баз даних, конфігурація ApplicationContext яких відрізняється лише тим, які профілі визначення бінів активні.

Першопричиною таких помилок є той факт, що фабрика EmbeddedDatabaseFactory зі Spring (використовується внутрішнім способом як елементом простору імен XML <jdbc:embedded-database>, так і конфігурацією EmbeddedDatabaseBuilder встановлює ім'я вбудованої бази даних на testdb, якщо не встановлено інше. У випадку <jdbc:embedded-database>, вбудованій базі даних зазвичай присвоюється ім'я, що дорівнює id біна (часто на кшталт dataSource). Таким чином, подальші спроби створити вбудовану базу даних не призводять до створення нової бази даних. Натомість повторно використовується та сама URL-адреса підключення JDBC, а спроби створити нову вбудовану базу даних фактично вказують на існуючу вбудовану базу даних, створену на основі тієї ж конфігурації.

Для вирішення цієї поширеної проблеми в Spring Framework 4.2 передбачено засоби підтримки генерації унікальних імен для вбудованих баз даних. Щоб активувати функцію використання згенерованих імен, використовуй один із наступних параметрів.

  • EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName()

  • EmbeddedDatabaseBuilder.generateUniqueName()

  • <jdbc:embedded-database generate-name="true" … >

Розширення підтримки вбудованих баз даних

Можна розширити засоби підтримки вбудованих баз даних JDBC у Spring двома способами:

  • Шляхом реалізації EmbeddedDatabaseConfigurer для забезпечення підтримки нового типу вбудованої бази даних.

  • Шляхом реалізації DataSourceFactory для забезпечення підтримки нової реалізації DataSource, наприклад, пула з'єднань, щоб керувати підключеннями до вбудованої бази даних.