or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-patterns.mdcore-operations.mddatabase-init.mddatasource.mdembedded-database.mdexception-translation.mdindex.mdkey-generation.mdlob-support.mdresult-parameter-handling.mdsimplified-operations.mdsqlrowset.mdtransactions.md
tile.json

database-init.mddocs/

Database Initialization

Spring JDBC provides support for initializing databases with SQL scripts, useful for setting up schemas, loading test data, and managing database migrations.

Core Interfaces

DatabasePopulator

Interface for populating databases.

public interface DatabasePopulator {
    void populate(Connection connection) throws ScriptException;
}

Main Classes

ResourceDatabasePopulator

Populates database from SQL script resources.

public class ResourceDatabasePopulator implements DatabasePopulator {
    public ResourceDatabasePopulator() { }
    public ResourceDatabasePopulator(Resource... scripts) { }
    public ResourceDatabasePopulator(boolean continueOnError, boolean ignoreFailedDrops, String sqlScriptEncoding, Resource... scripts) { }

    public void addScript(Resource script) { }
    public void addScripts(Resource... scripts) { }
    public void setScripts(Resource... scripts) { }
    public void setSqlScriptEncoding(String sqlScriptEncoding) { }
    public void setSeparator(String separator) { }
    public void setCommentPrefix(String commentPrefix) { }
    public void setCommentPrefixes(String... commentPrefixes) { }
    public void setBlockCommentStartDelimiter(String blockCommentStartDelimiter) { }
    public void setBlockCommentEndDelimiter(String blockCommentEndDelimiter) { }
    public void setContinueOnError(boolean continueOnError) { }
    public void setIgnoreFailedDrops(boolean ignoreFailedDrops) { }
    public void populate(Connection connection) throws ScriptException { }
}

ScriptUtils

Utility methods for executing SQL scripts.

public abstract class ScriptUtils {
    public static void executeSqlScript(Connection connection, Resource resource) throws ScriptException { }
    public static void executeSqlScript(Connection connection, EncodedResource resource) throws ScriptException { }
    public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops, String commentPrefixes[], String separator, String blockCommentStartDelimiter, String blockCommentEndDelimiter) throws ScriptException { }
}

DataSourceInitializer

Initializes DataSource with scripts on startup.

public class DataSourceInitializer implements InitializingBean, DisposableBean {
    public DataSourceInitializer() { }
    public void setDataSource(DataSource dataSource) { }
    public void setEnabled(boolean enabled) { }
    public void setDatabasePopulator(DatabasePopulator databasePopulator) { }
    public void setDatabaseCleaner(DatabasePopulator databaseCleaner) { }
}

Usage Examples

Basic Script Execution

import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.core.io.ClassPathResource;

DataSource dataSource = getDataSource();

ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(new ClassPathResource("schema.sql"));
populator.addScript(new ClassPathResource("data.sql"));

// Execute scripts
try (Connection conn = dataSource.getConnection()) {
    populator.populate(conn);
}

Multiple Scripts

ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScripts(
    new ClassPathResource("schema/tables.sql"),
    new ClassPathResource("schema/indexes.sql"),
    new ClassPathResource("schema/constraints.sql"),
    new ClassPathResource("data/users.sql"),
    new ClassPathResource("data/products.sql")
);

DatabasePopulatorUtils.execute(populator, dataSource);

Custom Configuration

ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.addScript(new ClassPathResource("init.sql"));
populator.setSqlScriptEncoding("UTF-8");
populator.setSeparator(";");
populator.setCommentPrefix("--");
populator.setContinueOnError(false);
populator.setIgnoreFailedDrops(true);

DatabasePopulatorUtils.execute(populator, dataSource);

Using ScriptUtils

import org.springframework.jdbc.datasource.init.ScriptUtils;

try (Connection conn = dataSource.getConnection()) {
    ScriptUtils.executeSqlScript(
        conn,
        new ClassPathResource("schema.sql")
    );
}

Spring Boot Configuration

# application.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    initialization-mode: always
  sql:
    init:
      mode: always
      schema-locations: classpath:schema.sql
      data-locations: classpath:data.sql
      continue-on-error: false
      separator: ;
      encoding: UTF-8

DataSourceInitializer Bean

@Configuration
public class DatabaseConfig {

    @Bean
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource);

        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScripts(
            new ClassPathResource("schema.sql"),
            new ClassPathResource("data.sql")
        );

        initializer.setDatabasePopulator(populator);
        return initializer;
    }
}

Environment-Specific Initialization

@Configuration
public class DatabaseInitConfig {

    @Value("${spring.profiles.active:default}")
    private String activeProfile;

    @Bean
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource);

        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();

        // Always load schema
        populator.addScript(new ClassPathResource("schema.sql"));

        // Load environment-specific data
        if ("dev".equals(activeProfile)) {
            populator.addScript(new ClassPathResource("data-dev.sql"));
        } else if ("test".equals(activeProfile)) {
            populator.addScript(new ClassPathResource("data-test.sql"));
        }

        initializer.setDatabasePopulator(populator);
        return initializer;
    }
}

Conditional Initialization

@Bean
@ConditionalOnProperty(name = "app.database.init.enabled", havingValue = "true")
public DataSourceInitializer conditionalInitializer(DataSource dataSource) {
    DataSourceInitializer initializer = new DataSourceInitializer();
    initializer.setDataSource(dataSource);

    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScript(new ClassPathResource("init.sql"));

    initializer.setDatabasePopulator(populator);
    return initializer;
}

Database Cleanup

@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
    DataSourceInitializer initializer = new DataSourceInitializer();
    initializer.setDataSource(dataSource);

    // Population scripts
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScript(new ClassPathResource("schema.sql"));
    initializer.setDatabasePopulator(populator);

    // Cleanup scripts (executed on shutdown)
    ResourceDatabasePopulator cleaner = new ResourceDatabasePopulator();
    cleaner.addScript(new ClassPathResource("cleanup.sql"));
    initializer.setDatabaseCleaner(cleaner);

    return initializer;
}

Test Database Initialization

@SpringBootTest
public class DatabaseTest {

    @Autowired
    private DataSource dataSource;

    @BeforeEach
    public void initDatabase() {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScripts(
            new ClassPathResource("test-schema.sql"),
            new ClassPathResource("test-data.sql")
        );
        populator.setContinueOnError(false);

        DatabasePopulatorUtils.execute(populator, dataSource);
    }

    @Test
    public void testQuery() {
        // Test with initialized data
    }
}

Dynamic Script Loading

public void initializeDatabaseFromFiles(DataSource dataSource, List<String> scriptPaths) {
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();

    for (String path : scriptPaths) {
        populator.addScript(new ClassPathResource(path));
    }

    DatabasePopulatorUtils.execute(populator, dataSource);
}

// Usage
List<String> scripts = Arrays.asList(
    "v1/schema.sql",
    "v1/data.sql",
    "v2/migration.sql",
    "v3/migration.sql"
);

initializeDatabaseFromFiles(dataSource, scripts);

Custom DatabasePopulator

public class CustomDatabasePopulator implements DatabasePopulator {

    @Override
    public void populate(Connection connection) throws ScriptException {
        try (Statement stmt = connection.createStatement()) {
            // Custom initialization logic
            stmt.execute("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(100))");
            stmt.execute("INSERT INTO users (name) VALUES ('Admin')");
            stmt.execute("INSERT INTO users (name) VALUES ('User')");
        } catch (SQLException e) {
            throw new ScriptException("Failed to populate database", e);
        }
    }
}

// Usage
DatabasePopulatorUtils.execute(new CustomDatabasePopulator(), dataSource);

Composite Populator

import org.springframework.jdbc.datasource.init.CompositeDatabasePopulator;

CompositeDatabasePopulator composite = new CompositeDatabasePopulator();

ResourceDatabasePopulator schemapopulator = new ResourceDatabasePopulator();
schemaPopulator.addScript(new ClassPathResource("schema.sql"));

ResourceDatabasePopulator dataPopulator = new ResourceDatabasePopulator();
dataPopulator.addScript(new ClassPathResource("data.sql"));

CustomDatabasePopulator customPopulator = new CustomDatabasePopulator();

composite.addPopulators(schemaPopulator, dataPopulator, customPopulator);

DatabasePopulatorUtils.execute(composite, dataSource);

SQL Script Format

Example schema.sql:

-- Create users table
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Create indexes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created_at ON users(created_at);

Example data.sql:

INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');
INSERT INTO users (name, email) VALUES ('Jane Smith', 'jane@example.com');
INSERT INTO users (name, email) VALUES ('Bob Johnson', 'bob@example.com');

Best Practices

  1. Separate schema and data - Different files for structure and content
  2. Use idempotent scripts - Use IF NOT EXISTS, DROP IF EXISTS
  3. Set proper encoding - UTF-8 for international characters
  4. Handle errors appropriately - continueOnError for test data
  5. Version control scripts - Track schema changes
  6. Test initialization - Verify scripts work correctly
  7. Use environment-specific data - Different data for dev/test/prod
  8. Document scripts - Add comments explaining purpose