El paquete org.springframework.jdbc.datasource.embedded proporciona soporte para motores de almacenamiento integrados en Java. Soporte HSQL, H2 y Derby se proporcionan de forma nativa. También puede utilizar la API extensible para conectar nuevos tipos de bases de datos integradas e implementaciones de DataSource.

¿Por qué utilizar una base de datos integrada?

Una base de datos integrada puede ser útil en la etapa de desarrollo del proyecto debido a su simplicidad. Los beneficios incluyen facilidad de configuración, tiempo de inicio rápido, capacidad de prueba y la capacidad de refinar rápidamente SQL durante el desarrollo.

Creación de una base de datos integrada utilizando Spring XML

Si necesita exponer una instancia de una base de datos integrada en Como bean en ApplicationContext en Spring, puede usar la etiqueta embedded-database en el espacio de nombres 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>

La configuración anterior crea una base de datos HSQL integrada que se completa con SQL desde recursos de schema.sql y test-data.sql en la raíz del classpath. Además, como práctica recomendada, la base de datos integrada recibe un nombre único. La base de datos integrada se pone a disposición del contenedor Spring como un bean de tipo javax.sql.DataSource, que luego se puede inyectar en objetos de acceso a datos según sea necesario.

Crear una base de datos integrada base de datos mediante programación

La clase EmbeddedDatabaseBuilder proporciona una API gratuita para crear una base de datos integrada mediante programación. Esto se puede utilizar si necesita crear una base de datos integrada en un entorno independiente o en una prueba de integración independiente, como en el siguiente ejemplo:

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();
// realiza acciones con la base de datos (EmbeddedDatabase extiende javax.sql.DataSource)
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()
// realiza acciones en la base de datos (EmbeddedDatabase extiende javax.sql.DataSource)
db.shutdown()

cm. javadoc EmbeddedDatabaseBuilder para obtener más detalles sobre todas las opciones admitidas.

También puede utilizar EmbeddedDatabaseBuilder para crear una base de datos integrada usando la configuración de Java, como se muestra en el siguiente ejemplo:

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

Seleccionar un tipo de base de datos integrada

Esta sección explica cómo seleccionar uno de los tres tipos de base de datos integrada. en bases de datos que soporta Spring. La sección incluye los siguientes temas:

  • Uso de HSQL

  • Uso de H2

  • Usando Derby

Uso de HSQL

Spring admite HSQL 1.8.0 y superior. HSQL es la base de datos integrada predeterminada si el tipo no se especifica explícitamente. Para especificar HSQL explícitamente, establezca el atributo type de la etiqueta embedded-database en HSQL. Si está utilizando la API de la herramienta de compilación, llame al método setType(EmbeddedDatabaseType) con el parámetro EmbeddedDatabaseType.HSQL.

Uso de H2

Spring admite la base de datos H2. Para habilitar H2, establezca el atributo type de la etiqueta embedded-database en H2. Si está utilizando la API de la herramienta de compilación, llame al método setType(EmbeddedDatabaseType) con el parámetro EmbeddedDatabaseType.H2.

Uso de Derby

Spring admite Apache Derby 10.5 y más alto. Para habilitar Derby, establezca el atributo type de la etiqueta embedded-database en DERBY. Si está utilizando la API de la herramienta de compilación, llame al método setType(EmbeddedDatabaseType) con el parámetro EmbeddedDatabaseType.DERBY.

Prueba de la lógica de acceso a datos utilizando una base de datos integrada

Las bases de datos integradas proporcionan una forma sencilla de probar el código para recuperar una muestra de datos. El siguiente ejemplo es una plantilla de prueba de integración de acceso a datos que utiliza una base de datos integrada. El uso de un patrón de este tipo puede resultar útil para casos de uso únicos en los que no es necesario reutilizar la base de datos integrada en todas las clases de prueba. Sin embargo, si necesita crear una base de datos integrada que se compartirá entre el conjunto de pruebas, utilice Spring TestContext Framework y configurar la base de datos integrada como un bean en ApplicationContext de Spring, como se describe arriba. La siguiente lista muestra el patrón de prueba:

Java

public class DataAccessIntegrationTestTemplate {
    private EmbeddedDatabase db;
    @BeforeEach
    public void setUp() {
        // creates an in-memory resident HSQL database filled with default scripts
        // classpath:schema.sql and 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() {
        // creates an in-memory resident HSQL database filled with default scripts
        // 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()
    }
}

Creación de nombres únicos para bases de datos integradas

Los equipos de desarrollo a menudo encuentran errores cuando trabajan con bases de datos integradas si su conjunto de pruebas intenta accidentalmente recrear instancias adicionales de la misma base de datos. Esto puede suceder con bastante facilidad si un archivo o clase de configuración XML con la anotación @Configuration es responsable de crear la base de datos integrada, y la configuración correspondiente luego se reutiliza en múltiples casos de prueba dentro de un único conjunto de pruebas (es decir, dentro de un único proceso JVM) - por ejemplo, pruebas de integración contra bases de datos integradas cuya configuración ApplicationContext difiere sólo en qué perfiles de definición de beans están activos.

La causa principal de tales errores es el hecho que la fábrica EmbeddedDatabaseFactory de Spring (utilizada internamente tanto por el elemento de espacio de nombres XML <jdbc:embedded-database> como por la configuración EmbeddedDatabaseBuilder para Java ) establece el nombre de la base de datos integrada en testdb a menos que se especifique lo contrario. En el caso de <jdbc:embedded-database>, la base de datos integrada normalmente recibe un nombre igual al id del bean (a menudo algo así como dataSource). Por lo tanto, los intentos posteriores de crear la base de datos incorporada no dan como resultado la creación de una nueva base de datos. En su lugar, se reutiliza la misma URL de conexión JDBC y los intentos de crear una nueva base de datos integrada en realidad apuntan a una base de datos integrada existente creada a partir de la misma configuración.

Para resolver este problema común, Spring Framework 4.2 proporciona soporte para generar nombres únicos para bases de datos integradas. Para habilitar la función para usar nombres generados, use uno de los siguientes parámetros.

  • EmbeddedDatabaseFactory.setGenerateUniqueDatabaseName()

  • EmbeddedDatabaseBuilder.generateUniqueName()

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

Ampliación del soporte de bases de datos nativas

Puede ampliar el soporte de bases de datos JDBC nativas de Spring de dos maneras:

  • Implementando EmbeddedDatabaseConfigurer para proporcionar soporte para un nuevo tipo de base de datos integrada.

  • Implementando DataSourceFactory para brindar soporte para una nueva implementación de DataSource, como un grupo de conexiones para administrar las conexiones a la base de datos integrada.

Le recomendamos que Contribuya con sugerencias de extensiones a la comunidad Spring en GitHub Issues.