Polish embedded database sections in reference manual
This commit is contained in:
@@ -3779,7 +3779,7 @@ as input. See the next section for details on how to define an `SqlParameter`.
|
|||||||
Explicit declarations are necessary if the database you use is not a Spring-supported
|
Explicit declarations are necessary if the database you use is not a Spring-supported
|
||||||
database. Currently Spring supports metadata lookup of stored procedure calls for the
|
database. Currently Spring supports metadata lookup of stored procedure calls for the
|
||||||
following databases: Apache Derby, DB2, MySQL, Microsoft SQL Server, Oracle, and Sybase.
|
following databases: Apache Derby, DB2, MySQL, Microsoft SQL Server, Oracle, and Sybase.
|
||||||
We also support metadata lookup of stored functions for: MySQL, Microsoft SQL Server,
|
We also support metadata lookup of stored functions for MySQL, Microsoft SQL Server,
|
||||||
and Oracle.
|
and Oracle.
|
||||||
====
|
====
|
||||||
|
|
||||||
@@ -4615,9 +4615,10 @@ testability, and the ability to rapidly evolve SQL during development.
|
|||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-xml]]
|
[[jdbc-embedded-database-xml]]
|
||||||
==== Creating an embedded database instance using Spring XML
|
==== Creating an embedded database using Spring XML
|
||||||
|
|
||||||
If you want to expose an embedded database instance as a bean in a Spring
|
If you want to expose an embedded database instance as a bean in a Spring
|
||||||
ApplicationContext, use the embedded-database tag in the spring-jdbc namespace:
|
`ApplicationContext`, use the `embedded-database` tag in the `spring-jdbc` namespace:
|
||||||
|
|
||||||
[source,xml,indent=0]
|
[source,xml,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
@@ -4629,37 +4630,66 @@ ApplicationContext, use the embedded-database tag in the spring-jdbc namespace:
|
|||||||
----
|
----
|
||||||
|
|
||||||
The preceding configuration creates an embedded HSQL database populated with SQL from
|
The preceding configuration creates an embedded HSQL database populated with SQL from
|
||||||
schema.sql and testdata.sql resources in the classpath. The database instance is made
|
`schema.sql` and `test-data.sql` resources in the root of the root of the classpath. The
|
||||||
available to the Spring container as a bean of type `javax.sql.DataSource`. This bean
|
database instance is made available to the Spring container as a bean of type
|
||||||
can then be injected into data access objects as needed.
|
`javax.sql.DataSource`. This bean can then be injected into data access objects as needed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-java]]
|
[[jdbc-embedded-database-java]]
|
||||||
==== Creating an embedded database instance programmatically
|
==== Creating an embedded database programmatically
|
||||||
|
|
||||||
The `EmbeddedDatabaseBuilder` class provides a fluent API for constructing an embedded
|
The `EmbeddedDatabaseBuilder` class provides a fluent API for constructing an embedded
|
||||||
database programmatically. Use this when you need to create an embedded database
|
database programmatically. Use this when you need to create an embedded database in a
|
||||||
instance in a standalone environment, such as a data access object unit test:
|
standalone environment or in a standalone integration test:
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
|
||||||
EmbeddedDatabase db = builder.setType(H2).addScript("my-schema.sql").addScript("my-test-data.sql").build();
|
.setType(H2)
|
||||||
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
|
.setScriptEncoding("UTF-8")
|
||||||
db.shutdown()
|
.ignoreFailedDrops(true)
|
||||||
|
.addScript("schema.sql")
|
||||||
|
.addScripts("user_data.sql", "country_data.sql")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
|
||||||
|
|
||||||
|
db.shutdown()
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The `EmbeddedDatabaseBuilder` can also be used to create an embedded database using Java
|
||||||
|
Config like in the following example.
|
||||||
|
|
||||||
|
[source,java,indent=0]
|
||||||
|
[subs="verbatim,quotes"]
|
||||||
|
----
|
||||||
|
@Configuration
|
||||||
|
public class DataSourceConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource dataSource() {
|
||||||
|
return new EmbeddedDatabaseBuilder()
|
||||||
|
.setType(H2)
|
||||||
|
.setScriptEncoding("UTF-8")
|
||||||
|
.ignoreFailedDrops(true)
|
||||||
|
.addScript("schema.sql")
|
||||||
|
.addScripts("user_data.sql", "country_data.sql")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-extension]]
|
[[jdbc-embedded-database-extension]]
|
||||||
==== Extending the embedded database support
|
==== Extending the embedded database support
|
||||||
|
|
||||||
Spring JDBC embedded database support can be extended in two ways:
|
Spring JDBC embedded database support can be extended in two ways:
|
||||||
|
|
||||||
* Implement `EmbeddedDatabaseConfigurer` to support a new embedded database type, such
|
* Implement `EmbeddedDatabaseConfigurer` to support a new embedded database type.
|
||||||
as Apache Derby.
|
* Implement `DataSourceFactory` to support a new `DataSource` implementation, such as a
|
||||||
* Implement `DataSourceFactory` to support a new DataSource implementation, such as a
|
connection pool to manage embedded database connections.
|
||||||
connection pool, to manage embedded database connections.
|
|
||||||
|
|
||||||
You are encouraged to contribute back extensions to the Spring community at
|
You are encouraged to contribute back extensions to the Spring community at
|
||||||
https://jira.spring.io/browse/SPR[jira.spring.io].
|
https://jira.spring.io/browse/SPR[jira.spring.io].
|
||||||
@@ -4668,8 +4698,8 @@ https://jira.spring.io/browse/SPR[jira.spring.io].
|
|||||||
|
|
||||||
[[jdbc-embedded-database-using-HSQL]]
|
[[jdbc-embedded-database-using-HSQL]]
|
||||||
==== Using HSQL
|
==== Using HSQL
|
||||||
Spring supports HSQL 1.8.0 and above. HSQL is the default embedded database if no type
|
Spring supports HSQL 1.8.0 and above. HSQL is the default embedded database if no type is
|
||||||
is specified explicitly. To specify HSQL explicitly, set the `type` attribute of the
|
specified explicitly. To specify HSQL explicitly, set the `type` attribute of the
|
||||||
`embedded-database` tag to `HSQL`. If you are using the builder API, call the
|
`embedded-database` tag to `HSQL`. If you are using the builder API, call the
|
||||||
`setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.HSQL`.
|
`setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.HSQL`.
|
||||||
|
|
||||||
@@ -4686,20 +4716,27 @@ Spring supports the H2 database as well. To enable H2, set the `type` attribute
|
|||||||
[[jdbc-embedded-database-using-Derby]]
|
[[jdbc-embedded-database-using-Derby]]
|
||||||
==== Using Derby
|
==== Using Derby
|
||||||
Spring also supports Apache Derby 10.5 and above. To enable Derby, set the `type`
|
Spring also supports Apache Derby 10.5 and above. To enable Derby, set the `type`
|
||||||
attribute of the `embedded-database` tag to `Derby`. If using the builder API, call the
|
attribute of the `embedded-database` tag to `DERBY`. If you are using the builder API,
|
||||||
`setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.Derby`.
|
call the `setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.DERBY`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-embedded-database-dao-testing]]
|
[[jdbc-embedded-database-dao-testing]]
|
||||||
==== Testing data access logic with an embedded database
|
==== Testing data access logic with an embedded database
|
||||||
Embedded databases provide a lightweight way to test data access code. The following is
|
|
||||||
a data access unit test template that uses an embedded database:
|
Embedded databases provide a lightweight way to test data access code. The following is a
|
||||||
|
data access integration test template that uses an embedded database. Using a template
|
||||||
|
like this can be useful for _one-offs_ when the embedded database does not need to be
|
||||||
|
reused across test classes. However, if you wish to create an embedded database that is
|
||||||
|
shared within a test suite, consider using the <<testcontext-framework,Spring TestContext
|
||||||
|
Framework>> and configuring the embedded database as a bean in the Spring
|
||||||
|
`ApplicationContext` as described in <<jdbc-embedded-database-xml>> and
|
||||||
|
<<jdbc-embedded-database-java>>.
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
public class DataAccessUnitTestTemplate {
|
public class DataAccessIntegrationTestTemplate {
|
||||||
|
|
||||||
private EmbeddedDatabase db;
|
private EmbeddedDatabase db;
|
||||||
|
|
||||||
@@ -4713,7 +4750,7 @@ a data access unit test template that uses an embedded database:
|
|||||||
@Test
|
@Test
|
||||||
public void testDataAccess() {
|
public void testDataAccess() {
|
||||||
JdbcTemplate template = new JdbcTemplate(db);
|
JdbcTemplate template = new JdbcTemplate(db);
|
||||||
template.query(...);
|
template.query( /* ... */ );
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -4726,7 +4763,6 @@ a data access unit test template that uses an embedded database:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-intializing-datasource]]
|
[[jdbc-intializing-datasource]]
|
||||||
=== Initializing a DataSource
|
=== Initializing a DataSource
|
||||||
The `org.springframework.jdbc.datasource.init` package provides support for initializing
|
The `org.springframework.jdbc.datasource.init` package provides support for initializing
|
||||||
@@ -4737,8 +4773,8 @@ an instance running on a server somewhere.
|
|||||||
|
|
||||||
|
|
||||||
[[jdbc-initializing-datasource-xml]]
|
[[jdbc-initializing-datasource-xml]]
|
||||||
==== Initializing a database instance using Spring XML
|
==== Initializing a database using Spring XML
|
||||||
If you want to initialize a database and you can provide a reference to a DataSource
|
If you want to initialize a database and you can provide a reference to a `DataSource`
|
||||||
bean, use the `initialize-database` tag in the `spring-jdbc` namespace:
|
bean, use the `initialize-database` tag in the `spring-jdbc` namespace:
|
||||||
|
|
||||||
[source,xml,indent=0]
|
[source,xml,indent=0]
|
||||||
@@ -4750,23 +4786,24 @@ bean, use the `initialize-database` tag in the `spring-jdbc` namespace:
|
|||||||
</jdbc:initialize-database>
|
</jdbc:initialize-database>
|
||||||
----
|
----
|
||||||
|
|
||||||
The example above runs the two scripts specified against the database: the first script
|
The example above executes the two scripts specified against the database: the first
|
||||||
is a schema creation, and the second is a test data set insert. The script locations can
|
script creates a schema, and the second populates tables with a test data set. The script
|
||||||
also be patterns with wildcards in the usual ant style used for resources in Spring
|
locations can also be patterns with wildcards in the usual ant style used for resources
|
||||||
(e.g. `classpath{asterisk}:/com/foo/{asterisk}{asterisk}/sql/{asterisk}-data.sql`).
|
in Spring (e.g.
|
||||||
If a pattern is used the scripts are executed in lexical order of their URL or filename.
|
`classpath{asterisk}:/com/foo/{asterisk}{asterisk}/sql/{asterisk}-data.sql`). If a
|
||||||
|
pattern is used, the scripts are executed in lexical order of their URL or filename.
|
||||||
|
|
||||||
The default behavior of the database initializer is to unconditionally execute the
|
The default behavior of the database initializer is to unconditionally execute the
|
||||||
scripts provided. This will not always be what you want, for instance if running against
|
scripts provided. This will not always be what you want, for instance, if you are
|
||||||
an existing database that already has test data in it. The likelihood of accidentally
|
executing the scripts against a database that already has test data in it. The likelihood
|
||||||
deleting data is reduced by the commonest pattern (as shown above) that creates the
|
of accidentally deleting data is reduced by following the common pattern (as shown above)
|
||||||
tables first and then inserts the data - the first step will fail if the tables already
|
of creating the tables first and then inserting the data -- the first step will fail if
|
||||||
exist.
|
the tables already exist.
|
||||||
|
|
||||||
However, to get more control over the creation and deletion of existing data, the XML
|
However, to gain more control over the creation and deletion of existing data, the XML
|
||||||
namespace provides a couple more options. The first is flag to switch the initialization
|
namespace provides a few additional options. The first is a flag to switch the
|
||||||
on and off. This can be set according to the environment (e.g. to pull a boolean value
|
initialization on and off. This can be set according to the environment (e.g. to pull a
|
||||||
from system properties or an environment bean), e.g.
|
boolean value from system properties or an environment bean), for example:
|
||||||
|
|
||||||
[source,xml,indent=0]
|
[source,xml,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
@@ -4779,7 +4816,7 @@ from system properties or an environment bean), e.g.
|
|||||||
|
|
||||||
The second option to control what happens with existing data is to be more tolerant of
|
The second option to control what happens with existing data is to be more tolerant of
|
||||||
failures. To this end you can control the ability of the initializer to ignore certain
|
failures. To this end you can control the ability of the initializer to ignore certain
|
||||||
errors in the SQL it executes from the scripts, e.g.
|
errors in the SQL it executes from the scripts, for example:
|
||||||
|
|
||||||
[source,xml,indent=0]
|
[source,xml,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
@@ -4789,62 +4826,68 @@ errors in the SQL it executes from the scripts, e.g.
|
|||||||
</jdbc:initialize-database>
|
</jdbc:initialize-database>
|
||||||
----
|
----
|
||||||
|
|
||||||
In this example we are saying we expect that sometimes the scripts will be run against
|
In this example we are saying we expect that sometimes the scripts will be executed
|
||||||
an empty database and there are some DROP statements in the scripts which would
|
against an empty database, and there are some `DROP` statements in the scripts which
|
||||||
therefore fail. So failed SQL `DROP` statements will be ignored, but other failures will
|
would therefore fail. So failed SQL `DROP` statements will be ignored, but other failures
|
||||||
cause an exception. This is useful if your SQL dialect doesn't support `DROP ... IF
|
will cause an exception. This is useful if your SQL dialect doesn't support `DROP ... IF
|
||||||
EXISTS` (or similar) but you want to unconditionally remove all test data before
|
EXISTS` (or similar) but you want to unconditionally remove all test data before
|
||||||
re-creating it. In that case the first script is usually a set of drops, followed by a
|
re-creating it. In that case the first script is usually a set of `DROP` statements,
|
||||||
set of `CREATE` statements.
|
followed by a set of `CREATE` statements.
|
||||||
|
|
||||||
The `ignore-failures` option can be set to `NONE` (the default), `DROPS` (ignore failed
|
The `ignore-failures` option can be set to `NONE` (the default), `DROPS` (ignore failed
|
||||||
drops) or `ALL` (ignore all failures).
|
drops), or `ALL` (ignore all failures).
|
||||||
|
|
||||||
If you need more control than you get from the XML namespace, you can simply use the
|
If you need more control than you get from the XML namespace, you can simply use the
|
||||||
`DataSourceInitializer` directly, and define it as a component in your application.
|
`DataSourceInitializer` directly and define it as a component in your application.
|
||||||
|
|
||||||
|
|
||||||
[[jdbc-client-component-initialization]]
|
[[jdbc-client-component-initialization]]
|
||||||
===== Initialization of Other Components that Depend on the Database
|
===== Initialization of other components that depend on the database
|
||||||
|
|
||||||
A large class of applications can just use the database initializer with no further
|
A large class of applications can just use the database initializer with no further
|
||||||
complications: those that do not use the database until after the Spring context has
|
complications: those that do not use the database until after the Spring context has
|
||||||
started. If your application is __not__ one of those then you might need to read the
|
started. If your application is __not__ one of those then you might need to read the rest
|
||||||
rest of this section.
|
of this section.
|
||||||
|
|
||||||
The database initializer depends on a data source instance and runs the scripts provided
|
The database initializer depends on a `DataSource` instance and executes the scripts
|
||||||
in its initialization callback (c.f. `init-method` in an XML bean definition or
|
provided in its initialization callback (analogous to an `init-method` in an XML bean
|
||||||
`InitializingBean`). If other beans depend on the same data source and also use the data
|
definition, a `@PostConstruct` method in a component, or the `afterPropertiesSet()`
|
||||||
source in an initialization callback then there might be a problem because the data has
|
method in a component that implements `InitializingBean`). If other beans depend on the
|
||||||
not yet been initialized. A common example of this is a cache that initializes eagerly
|
same data source and also use the data source in an initialization callback, then there
|
||||||
and loads up data from the database on application startup.
|
might be a problem because the data has not yet been initialized. A common example of
|
||||||
|
this is a cache that initializes eagerly and loads data from the database on application
|
||||||
|
startup.
|
||||||
|
|
||||||
To get round this issue you two options: change your cache initialization strategy to a
|
To get around this issue you have two options: change your cache initialization strategy
|
||||||
later phase, or ensure that the database initializer is initialized first.
|
to a later phase, or ensure that the database initializer is initialized first.
|
||||||
|
|
||||||
The first option might be easy if the application is in your control, and not otherwise.
|
The first option might be easy if the application is in your control, and not otherwise.
|
||||||
Some suggestions for how to implement this are
|
Some suggestions for how to implement this include:
|
||||||
|
|
||||||
* Make the cache initialize lazily on first usage, which improves application startup time
|
* Make the cache initialize lazily on first usage, which improves application startup
|
||||||
|
time.
|
||||||
* Have your cache or a separate component that initializes the cache implement
|
* Have your cache or a separate component that initializes the cache implement
|
||||||
`Lifecycle` or `SmartLifecycle`. When the application context starts up a
|
`Lifecycle` or `SmartLifecycle`. When the application context starts up a
|
||||||
`SmartLifecycle` can be automatically started if its `autoStartup` flag is set, and a
|
`SmartLifecycle` can be automatically started if its `autoStartup` flag is set, and a
|
||||||
`Lifecycle` can be started manually by calling
|
`Lifecycle` can be started manually by calling `ConfigurableApplicationContext.start()`
|
||||||
`ConfigurableApplicationContext.start()` on the enclosing context.
|
on the enclosing context.
|
||||||
* Use a Spring `ApplicationEvent` or similar custom observer mechanism to trigger the
|
* Use a Spring `ApplicationEvent` or similar custom observer mechanism to trigger the
|
||||||
cache initialization. `ContextRefreshedEvent` is always published by the context when
|
cache initialization. `ContextRefreshedEvent` is always published by the context when
|
||||||
it is ready for use (after all beans have been initialized), so that is often a useful
|
it is ready for use (after all beans have been initialized), so that is often a useful
|
||||||
hook (this is how the `SmartLifecycle` works by default).
|
hook (this is how the `SmartLifecycle` works by default).
|
||||||
|
|
||||||
The second option can also be easy. Some suggestions on how to implement this are
|
The second option can also be easy. Some suggestions on how to implement this include:
|
||||||
|
|
||||||
* Rely on Spring BeanFactory default behavior, which is that beans are initialized in
|
* Rely on the default behavior of the Spring `BeanFactory`, which is that beans are
|
||||||
registration order. You can easily arrange that by adopting the common practice of a
|
initialized in registration order. You can easily arrange that by adopting the common
|
||||||
set of <import/> elements that order your application modules, and ensure that the
|
practice of a set of `<import/>` elements in XML configuration that order your
|
||||||
database and database initialization are listed first
|
application modules, and ensure that the database and database initialization are
|
||||||
* Separate the datasource and the business components that use it and control their
|
listed first.
|
||||||
startup order by putting them in separate ApplicationContext instances (e.g. parent
|
* Separate the `DataSource` and the business components that use it, and control their
|
||||||
has the datasource and child has the business components). This structure is common in
|
startup order by putting them in separate `ApplicationContext` instances (e.g. the
|
||||||
Spring web applications, but can be more generally applied.
|
parent context contains the `DataSource`, and child context contains the business
|
||||||
|
components). This structure is common in Spring web applications but can be more
|
||||||
|
generally applied.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user