Spring JDBC provides support for initializing databases with SQL scripts, useful for setting up schemas, loading test data, and managing database migrations.
Interface for populating databases.
public interface DatabasePopulator {
void populate(Connection connection) throws ScriptException;
}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 { }
}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 { }
}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) { }
}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);
}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);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);import org.springframework.jdbc.datasource.init.ScriptUtils;
try (Connection conn = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(
conn,
new ClassPathResource("schema.sql")
);
}# 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@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;
}
}@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;
}
}@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;
}@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;
}@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
}
}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);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);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);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');