An SQL database can be initialized in different ways depending on what your stack is.
Of course, you can also do it manually, provided the database is a separate process.
It is recommended to use a single mechanism for schema generation.
[[howto.data-initialization.using-jpa]]
=== Initialize a Database Using JPA
JPA has features for DDL generation, and these can be set up to run on startup against the database.
This is controlled through two external properties:
* `spring.jpa.generate-ddl` (boolean) switches the feature on and off and is vendor independent.
* `spring.jpa.hibernate.ddl-auto` (enum) is a Hibernate feature that controls the behavior in a more fine-grained way.
This feature is described in more detail later in this guide.
[[howto.data-initialization.using-hibernate]]
=== Initialize a Database Using Hibernate
You can set `spring.jpa.hibernate.ddl-auto` explicitly and the standard Hibernate property values are `none`, `validate`, `update`, `create`, and `create-drop`.
Spring Boot chooses a default value for you based on whether it thinks your database is embedded.
It defaults to `create-drop` if no schema manager has been detected or `none` in all other cases.
An embedded database is detected by looking at the `Connection` type and JDBC url.
`hsqldb`, `h2`, and `derby` are candidates, and others are not.
Be careful when switching from in-memory to a '`real`' database that you do not make assumptions about the existence of the tables and data in the new platform.
You either have to set `ddl-auto` explicitly or use one of the other mechanisms to initialize the database.
NOTE: You can output the schema creation by enabling the `org.hibernate.SQL` logger.
This is done for you automatically if you enable the <<features#features.logging.console-output,debug mode>>.
In addition, a file named `import.sql` in the root of the classpath is executed on startup if Hibernate creates the schema from scratch (that is, if the `ddl-auto` property is set to `create` or `create-drop`).
This can be useful for demos and for testing if you are careful but is probably not something you want to be on the classpath in production.
It is a Hibernate feature (and has nothing to do with Spring).
Spring Boot can automatically create the schema (DDL scripts) of your JDBC `DataSource` or R2DBC `ConnectionFactory` and initialize its data (DML scripts).
By default, it loads schema scripts from `optional:classpath*:schema.sql` and data scripts from `optional:classpath*:data.sql`.
The locations of these schema and data scripts can customized using configprop:spring.sql.init.schema-locations[] and configprop:spring.sql.init.data-locations[] respectively.
The `optional:` prefix means that the application will start when the files do not exist.
To have the application fail to start when the files are absent, remove the `optional:` prefix.
In addition, Spring Boot processes the `optional:classpath*:schema-$\{platform}.sql` and `optional:classpath*:data-$\{platform}.sql` files (if present), where `$\{platform}` is the value of configprop:spring.sql.init.platform[].
By default, Spring Boot enables the fail-fast feature of its script-based database initializer.
This means that, if the scripts cause exceptions, the application fails to start.
You can tune that behavior by setting configprop:spring.sql.init.continue-on-error[].
Script-based `DataSource` initialization is performed, by default, before any JPA `EntityManagerFactory` beans are created.
`schema.sql` can be used to create the schema for JPA-managed entities and `data.sql` can be used to populate it.
While we do not recommend using multiple data source initialization technologies, if you want script-based `DataSource` initialization to be able to build upon the schema creation performed by Hibernate, set configprop:spring.jpa.defer-datasource-initialization[] to `true`.
This will defer data source initialization until after any `EntityManagerFactory` beans have been created and initialized.
`schema.sql` can then be used to make additions to any schema creation performed by Hibernate and `data.sql` can be used to populate it.
If you are using a <<howto#howto.data-initialization.migration-tool,Higher-level Database Migration Tool>>, like Flyway or Liquibase, you should use them alone to create and initialize the schema.
Using the basic `schema.sql` and `data.sql` scripts alongside Flyway or Liquibase is not recommended and support will be removed in a future release.
If you need to initialize test data using a higher-level database migration tool, please see the sections about <<howto#howto.data-initialization.migration-tool.flyway-tests, Flyway>> and <<howto#howto.data-initialization.migration-tool.liquibase-tests, Liquibase>>.
Rather than using `db/migration`, the preceding configuration sets the directory to use according to the type of the database (such as `db/migration/mysql` for MySQL).
The list of supported databases is available in {spring-boot-module-code}/jdbc/DatabaseDriver.java[`DatabaseDriver`].
Migrations can also be written in Java.
Flyway will be auto-configured with any beans that implement `JavaMigration`.
{spring-boot-autoconfigure-module-code}/flyway/FlywayProperties.java[`FlywayProperties`] provides most of Flyway's settings and a small set of additional properties that can be used to disable the migrations or switch off the location checking.
If you need more control over the configuration, consider registering a `FlywayConfigurationCustomizer` bean.
Spring Boot calls `Flyway.migrate()` to perform the database migration.
If you would like more control, provide a `@Bean` that implements {spring-boot-autoconfigure-module-code}/flyway/FlywayMigrationStrategy.java[`FlywayMigrationStrategy`].
Flyway supports SQL and Java https://flywaydb.org/documentation/concepts/callbacks[callbacks].
To use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` directory.
To use Java-based callbacks, create one or more beans that implement `Callback`.
Any such beans are automatically registered with `Flyway`.
They can be ordered by using `@Order` or by implementing `Ordered`.
Beans that implement the deprecated `FlywayCallback` interface can also be detected, however they cannot be used alongside `Callback` beans.
By default, Flyway autowires the (`@Primary`) `DataSource` in your context and uses that for migrations.
If you like to use a different `DataSource`, you can create one and mark its `@Bean` as `@FlywayDataSource`.
If you do so and want two data sources, remember to create another one and mark it as `@Primary`.
Alternatively, you can use Flyway's native `DataSource` by setting `spring.flyway.[url,user,password]` in external properties.
Setting either `spring.flyway.url` or `spring.flyway.user` is sufficient to cause Flyway to use its own `DataSource`.
If any of the three properties has not been set, the value of its equivalent `spring.datasource` property will be used.
You can also use Flyway to provide data for specific scenarios.
For example, you can place test-specific migrations in `src/test/resources` and they are run only when your application starts for testing.
Also, you can use profile-specific configuration to customize `spring.flyway.locations` so that certain migrations run only when a particular profile is active.
For example, in `application-dev.properties`, you might specify the following setting:
==== Execute Liquibase Database Migrations on Startup
To automatically run Liquibase database migrations on startup, add the `org.liquibase:liquibase-core` to your classpath.
[NOTE]
====
When you add the `org.liquibase:liquibase-core` to your classpath, database migrations run by default for both during application startup and before your tests run.
This behavior can be customized by using the configprop:spring.liquibase.enabled[] property, setting different values in the `main` and `test` configurations.
By default, the master change log is read from `db/changelog/db.changelog-master.yaml`, but you can change the location by setting `spring.liquibase.change-log`.
In addition to YAML, Liquibase also supports JSON, XML, and SQL change log formats.
By default, Liquibase autowires the (`@Primary`) `DataSource` in your context and uses that for migrations.
If you need to use a different `DataSource`, you can create one and mark its `@Bean` as `@LiquibaseDataSource`.
If you do so and you want two data sources, remember to create another one and mark it as `@Primary`.
Alternatively, you can use Liquibase's native `DataSource` by setting `spring.liquibase.[driver-class-name,url,user,password]` in external properties.
Setting either `spring.liquibase.url` or `spring.liquibase.user` is sufficient to cause Liquibase to use its own `DataSource`.
If any of the three properties has not been set, the value of its equivalent `spring.datasource` property will be used.
See {spring-boot-autoconfigure-module-code}/liquibase/LiquibaseProperties.java[`LiquibaseProperties`] for details about available settings such as contexts, the default schema, and others.
If you want to create Flyway migrations which populate your test database, place them in `src/test/resources/db/migration`.
A file named, for example, `src/test/resources/db/migration/V9999__test-data.sql` will be executed after your production migrations and only if you're running the tests.
You can use this file to create the needed test data.
This file will not be packaged in your uber jar or your container.
If you want to create Liquibase migrations which populate your test database, you have to create a test changelog which also includes the production changelog.
First, you need to configure Liquibase to use a different changelog when running the tests.
One way to do this is to create a Spring Boot `test` profile and put the Liquibase properties in there.
For that, create a file named `src/test/resources/application-test.properties` and put the following property in there:
This changelog will be used when the tests are run and it will not be packaged in your uber jar or your container.
It includes the production changelog and then declares a new changeset, whose `runOrder: last` setting specifies that it runs after all the production changesets have been run.
You can now use for example the https://docs.liquibase.com/change-types/insert.html[insert changeset] to insert data or the https://docs.liquibase.com/change-types/sql.html[sql changeset] to execute SQL directly.
The last thing to do is to configure Spring Boot to activate the `test` profile when running tests.
To do this, you can add the `@ActiveProfiles("test")` annotation to your `@SpringBootTest` annotated test classes.
Database initialization is performed while the application is starting up as part of application context refresh.
To allow an initialized database to be accessed during startup, beans that act as database initializers and beans that require that database to have been initialized are detected automatically.
Beans whose initialization depends upon the database having been initialized are configured to depend upon those that initialize it.
If, during startup, your application tries to access the database and it has not been initialized, you can configure additional detection of beans that initialize the database and require the database to have been initialized.
Spring Boot will automatically detect beans of the following types that initialize an SQL database:
- `DataSourceScriptDatabaseInitializer`
- `EntityManagerFactory`
- `Flyway`
- `FlywayMigrationInitializer`
- `R2dbcScriptDatabaseInitializer`
- `SpringLiquibase`
If you are using a third-party starter for a database initialization library, it may provide a detector such that beans of other types are also detected automatically.