An SQL database can be initialized in different ways depending on what your stack is. Or of course you can do it manually as long as the database is a separate process.
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. See below for more detail.You can set spring.jpa.hibernate.ddl-auto
explicitly and the standard Hibernate property
values are none
, validate
, update
, create
, create-drop
. Spring Boot chooses a
default value for you based on whether it thinks your database is embedded (default
create-drop
) or not (default none
). An embedded database is detected by looking at the
Connection
type: hsqldb
, h2
and derby
are embedded, the rest are not. Be careful
when switching from in-memory to a ‘real’ database that you don’t 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 |
In addition, a file named import.sql
in the root of the classpath will be executed on
startup. This can be useful for demos and for testing if you are careful, but probably
not something you want to be on the classpath in production. It is a Hibernate feature
(nothing to do with Spring).
Spring JDBC has a DataSource
initializer feature. Spring Boot enables it by default and
loads SQL from the standard locations schema.sql
and data.sql
(in the root of the
classpath). In addition Spring Boot will load the schema-${platform}.sql
and data-${platform}.sql
files (if present), where
platform
is the value of spring.datasource.platform
, e.g. you might choose to set
it to the vendor name of the database (hsqldb
, h2
, oracle
, mysql
,
postgresql
etc.). Spring Boot enables the fail-fast feature of the Spring JDBC
initializer by default, so if the scripts cause exceptions the application will fail
to start. The script locations can be changed by setting spring.datasource.schema
and
spring.datasource.data
, and neither location will be processed if
spring.datasource.initialize=false
.
To disable the fail-fast you can set spring.datasource.continue-on-error=true
. This can be
useful once an application has matured and been deployed a few times, since the scripts
can act as ‘poor man’s migrations’ — inserts that fail mean that the data is already
there, so there would be no need to prevent the application from running, for instance.
If you want to use the schema.sql
initialization in a JPA app (with
Hibernate) then ddl-auto=create-drop
will lead to errors if
Hibernate tries to create the same tables. To avoid those errors set
ddl-auto
explicitly to "" (preferable) or "none". Whether or not you use
ddl-auto=create-drop
you can always use data.sql
to initialize new
data.
If you are using Spring Batch then it comes pre-packaged with SQL initialization scripts
for most popular database platforms. Spring Boot will detect your database type, and
execute those scripts by default, and in this case will switch the fail fast setting to
false (errors are logged but do not prevent the application from starting). This is
because the scripts are known to be reliable and generally do not contain bugs, so errors
are ignorable, and ignoring them makes the scripts idempotent. You can switch off the
initialization explicitly using spring.batch.initializer.enabled=false
.
Spring Boot works fine with higher level migration tools Flyway (SQL-based) and Liquibase (XML). In general we prefer Flyway because it is easier on the eyes, and it isn’t very common to need platform independence: usually only one or at most couple of platforms is needed.
To automatically run Flyway database migrations on startup, add the
org.flywaydb:flyway-core
to your classpath.
The migrations are scripts in the form V<VERSION>__<NAME>.sql
(with <VERSION>
an
underscore-separated version, e.g. ‘1’ or ‘2_1’). By default they live in a folder
classpath:db/migration
but you can modify that using flyway.locations
(a list). See
the Flyway class from flyway-core for details of available settings like schemas etc. In
addition Spring Boot provides a small set of properties in
FlywayProperties
that can be used to disable the migrations, or switch off the location checking.
Tip | |
---|---|
If you want to make use of Flyway
callbacks, those scripts should also live in the |
By default Flyway will autowire the (@Primary
) DataSource
in your context and
use that for migrations. If you like to use a different DataSource
you can create
one and mark its @Bean
as @FlywayDataSource
- if you do that remember to create
another one and mark it as @Primary
if you want two data sources.
Or you can use Flyway’s native DataSource
by setting flyway.[url,user,password]
in external properties.
There is a Flyway sample so you can see how to set things up.
To automatically run Liquibase database migrations on startup, add the
org.liquibase:liquibase-core
to your classpath.
The master change log is by default read from db/changelog/db.changelog-master.yaml
but
can be set using liquibase.change-log
. See
LiquibaseProperties
for details of available settings like contexts, default schema etc.
There is a Liquibase sample so you can see how to set things up.