Skip to content

Commit c5b9b39

Browse files
committed
Polish embedded database sections in reference manual
1 parent 1c8ac2b commit c5b9b39

File tree

1 file changed

+119
-76
lines changed

1 file changed

+119
-76
lines changed

src/asciidoc/data-access.adoc

Lines changed: 119 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3779,7 +3779,7 @@ as input. See the next section for details on how to define an `SqlParameter`.
37793779
Explicit declarations are necessary if the database you use is not a Spring-supported
37803780
database. Currently Spring supports metadata lookup of stored procedure calls for the
37813781
following databases: Apache Derby, DB2, MySQL, Microsoft SQL Server, Oracle, and Sybase.
3782-
We also support metadata lookup of stored functions for: MySQL, Microsoft SQL Server,
3782+
We also support metadata lookup of stored functions for MySQL, Microsoft SQL Server,
37833783
and Oracle.
37843784
====
37853785

@@ -4615,9 +4615,10 @@ testability, and the ability to rapidly evolve SQL during development.
46154615

46164616

46174617
[[jdbc-embedded-database-xml]]
4618-
==== Creating an embedded database instance using Spring XML
4618+
==== Creating an embedded database using Spring XML
4619+
46194620
If you want to expose an embedded database instance as a bean in a Spring
4620-
ApplicationContext, use the embedded-database tag in the spring-jdbc namespace:
4621+
`ApplicationContext`, use the `embedded-database` tag in the `spring-jdbc` namespace:
46214622

46224623
[source,xml,indent=0]
46234624
[subs="verbatim,quotes"]
@@ -4629,37 +4630,66 @@ ApplicationContext, use the embedded-database tag in the spring-jdbc namespace:
46294630
----
46304631

46314632
The preceding configuration creates an embedded HSQL database populated with SQL from
4632-
schema.sql and testdata.sql resources in the classpath. The database instance is made
4633-
available to the Spring container as a bean of type `javax.sql.DataSource`. This bean
4634-
can then be injected into data access objects as needed.
4633+
`schema.sql` and `test-data.sql` resources in the root of the root of the classpath. The
4634+
database instance is made available to the Spring container as a bean of type
4635+
`javax.sql.DataSource`. This bean can then be injected into data access objects as needed.
46354636

46364637

46374638

46384639
[[jdbc-embedded-database-java]]
4639-
==== Creating an embedded database instance programmatically
4640+
==== Creating an embedded database programmatically
4641+
46404642
The `EmbeddedDatabaseBuilder` class provides a fluent API for constructing an embedded
4641-
database programmatically. Use this when you need to create an embedded database
4642-
instance in a standalone environment, such as a data access object unit test:
4643+
database programmatically. Use this when you need to create an embedded database in a
4644+
standalone environment or in a standalone integration test:
46434645

46444646
[source,java,indent=0]
46454647
[subs="verbatim,quotes"]
46464648
----
4647-
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
4648-
EmbeddedDatabase db = builder.setType(H2).addScript("my-schema.sql").addScript("my-test-data.sql").build();
4649-
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
4650-
db.shutdown()
4649+
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
4650+
.setType(H2)
4651+
.setScriptEncoding("UTF-8")
4652+
.ignoreFailedDrops(true)
4653+
.addScript("schema.sql")
4654+
.addScripts("user_data.sql", "country_data.sql")
4655+
.build();
4656+
4657+
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
4658+
4659+
db.shutdown()
4660+
----
4661+
4662+
The `EmbeddedDatabaseBuilder` can also be used to create an embedded database using Java
4663+
Config like in the following example.
4664+
4665+
[source,java,indent=0]
4666+
[subs="verbatim,quotes"]
46514667
----
4668+
@Configuration
4669+
public class DataSourceConfig {
46524670
4671+
@Bean
4672+
public DataSource dataSource() {
4673+
return new EmbeddedDatabaseBuilder()
4674+
.setType(H2)
4675+
.setScriptEncoding("UTF-8")
4676+
.ignoreFailedDrops(true)
4677+
.addScript("schema.sql")
4678+
.addScripts("user_data.sql", "country_data.sql")
4679+
.build();
4680+
}
4681+
}
4682+
----
46534683

46544684

46554685
[[jdbc-embedded-database-extension]]
46564686
==== Extending the embedded database support
4687+
46574688
Spring JDBC embedded database support can be extended in two ways:
46584689

4659-
* Implement `EmbeddedDatabaseConfigurer` to support a new embedded database type, such
4660-
as Apache Derby.
4661-
* Implement `DataSourceFactory` to support a new DataSource implementation, such as a
4662-
connection pool, to manage embedded database connections.
4690+
* Implement `EmbeddedDatabaseConfigurer` to support a new embedded database type.
4691+
* Implement `DataSourceFactory` to support a new `DataSource` implementation, such as a
4692+
connection pool to manage embedded database connections.
46634693

46644694
You are encouraged to contribute back extensions to the Spring community at
46654695
https://jira.spring.io/browse/SPR[jira.spring.io].
@@ -4668,8 +4698,8 @@ https://jira.spring.io/browse/SPR[jira.spring.io].
46684698

46694699
[[jdbc-embedded-database-using-HSQL]]
46704700
==== Using HSQL
4671-
Spring supports HSQL 1.8.0 and above. HSQL is the default embedded database if no type
4672-
is specified explicitly. To specify HSQL explicitly, set the `type` attribute of the
4701+
Spring supports HSQL 1.8.0 and above. HSQL is the default embedded database if no type is
4702+
specified explicitly. To specify HSQL explicitly, set the `type` attribute of the
46734703
`embedded-database` tag to `HSQL`. If you are using the builder API, call the
46744704
`setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.HSQL`.
46754705

@@ -4686,20 +4716,27 @@ Spring supports the H2 database as well. To enable H2, set the `type` attribute
46864716
[[jdbc-embedded-database-using-Derby]]
46874717
==== Using Derby
46884718
Spring also supports Apache Derby 10.5 and above. To enable Derby, set the `type`
4689-
attribute of the `embedded-database` tag to `Derby`. If using the builder API, call the
4690-
`setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.Derby`.
4719+
attribute of the `embedded-database` tag to `DERBY`. If you are using the builder API,
4720+
call the `setType(EmbeddedDatabaseType)` method with `EmbeddedDatabaseType.DERBY`.
46914721

46924722

46934723

46944724
[[jdbc-embedded-database-dao-testing]]
46954725
==== Testing data access logic with an embedded database
4696-
Embedded databases provide a lightweight way to test data access code. The following is
4697-
a data access unit test template that uses an embedded database:
4726+
4727+
Embedded databases provide a lightweight way to test data access code. The following is a
4728+
data access integration test template that uses an embedded database. Using a template
4729+
like this can be useful for _one-offs_ when the embedded database does not need to be
4730+
reused across test classes. However, if you wish to create an embedded database that is
4731+
shared within a test suite, consider using the <<testcontext-framework,Spring TestContext
4732+
Framework>> and configuring the embedded database as a bean in the Spring
4733+
`ApplicationContext` as described in <<jdbc-embedded-database-xml>> and
4734+
<<jdbc-embedded-database-java>>.
46984735

46994736
[source,java,indent=0]
47004737
[subs="verbatim,quotes"]
47014738
----
4702-
public class DataAccessUnitTestTemplate {
4739+
public class DataAccessIntegrationTestTemplate {
47034740
47044741
private EmbeddedDatabase db;
47054742
@@ -4713,7 +4750,7 @@ a data access unit test template that uses an embedded database:
47134750
@Test
47144751
public void testDataAccess() {
47154752
JdbcTemplate template = new JdbcTemplate(db);
4716-
template.query(...);
4753+
template.query( /* ... */ );
47174754
}
47184755
47194756
@After
@@ -4726,7 +4763,6 @@ a data access unit test template that uses an embedded database:
47264763

47274764

47284765

4729-
47304766
[[jdbc-intializing-datasource]]
47314767
=== Initializing a DataSource
47324768
The `org.springframework.jdbc.datasource.init` package provides support for initializing
@@ -4737,8 +4773,8 @@ an instance running on a server somewhere.
47374773

47384774

47394775
[[jdbc-initializing-datasource-xml]]
4740-
==== Initializing a database instance using Spring XML
4741-
If you want to initialize a database and you can provide a reference to a DataSource
4776+
==== Initializing a database using Spring XML
4777+
If you want to initialize a database and you can provide a reference to a `DataSource`
47424778
bean, use the `initialize-database` tag in the `spring-jdbc` namespace:
47434779

47444780
[source,xml,indent=0]
@@ -4750,23 +4786,24 @@ bean, use the `initialize-database` tag in the `spring-jdbc` namespace:
47504786
</jdbc:initialize-database>
47514787
----
47524788

4753-
The example above runs the two scripts specified against the database: the first script
4754-
is a schema creation, and the second is a test data set insert. The script locations can
4755-
also be patterns with wildcards in the usual ant style used for resources in Spring
4756-
(e.g. `classpath{asterisk}:/com/foo/{asterisk}{asterisk}/sql/{asterisk}-data.sql`).
4757-
If a pattern is used the scripts are executed in lexical order of their URL or filename.
4789+
The example above executes the two scripts specified against the database: the first
4790+
script creates a schema, and the second populates tables with a test data set. The script
4791+
locations can also be patterns with wildcards in the usual ant style used for resources
4792+
in Spring (e.g.
4793+
`classpath{asterisk}:/com/foo/{asterisk}{asterisk}/sql/{asterisk}-data.sql`). If a
4794+
pattern is used, the scripts are executed in lexical order of their URL or filename.
47584795

47594796
The default behavior of the database initializer is to unconditionally execute the
4760-
scripts provided. This will not always be what you want, for instance if running against
4761-
an existing database that already has test data in it. The likelihood of accidentally
4762-
deleting data is reduced by the commonest pattern (as shown above) that creates the
4763-
tables first and then inserts the data - the first step will fail if the tables already
4764-
exist.
4797+
scripts provided. This will not always be what you want, for instance, if you are
4798+
executing the scripts against a database that already has test data in it. The likelihood
4799+
of accidentally deleting data is reduced by following the common pattern (as shown above)
4800+
of creating the tables first and then inserting the data -- the first step will fail if
4801+
the tables already exist.
47654802

4766-
However, to get more control over the creation and deletion of existing data, the XML
4767-
namespace provides a couple more options. The first is flag to switch the initialization
4768-
on and off. This can be set according to the environment (e.g. to pull a boolean value
4769-
from system properties or an environment bean), e.g.
4803+
However, to gain more control over the creation and deletion of existing data, the XML
4804+
namespace provides a few additional options. The first is a flag to switch the
4805+
initialization on and off. This can be set according to the environment (e.g. to pull a
4806+
boolean value from system properties or an environment bean), for example:
47704807

47714808
[source,xml,indent=0]
47724809
[subs="verbatim,quotes"]
@@ -4779,7 +4816,7 @@ from system properties or an environment bean), e.g.
47794816

47804817
The second option to control what happens with existing data is to be more tolerant of
47814818
failures. To this end you can control the ability of the initializer to ignore certain
4782-
errors in the SQL it executes from the scripts, e.g.
4819+
errors in the SQL it executes from the scripts, for example:
47834820

47844821
[source,xml,indent=0]
47854822
[subs="verbatim,quotes"]
@@ -4789,62 +4826,68 @@ errors in the SQL it executes from the scripts, e.g.
47894826
</jdbc:initialize-database>
47904827
----
47914828

4792-
In this example we are saying we expect that sometimes the scripts will be run against
4793-
an empty database and there are some DROP statements in the scripts which would
4794-
therefore fail. So failed SQL `DROP` statements will be ignored, but other failures will
4795-
cause an exception. This is useful if your SQL dialect doesn't support `DROP ... IF
4829+
In this example we are saying we expect that sometimes the scripts will be executed
4830+
against an empty database, and there are some `DROP` statements in the scripts which
4831+
would therefore fail. So failed SQL `DROP` statements will be ignored, but other failures
4832+
will cause an exception. This is useful if your SQL dialect doesn't support `DROP ... IF
47964833
EXISTS` (or similar) but you want to unconditionally remove all test data before
4797-
re-creating it. In that case the first script is usually a set of drops, followed by a
4798-
set of `CREATE` statements.
4834+
re-creating it. In that case the first script is usually a set of `DROP` statements,
4835+
followed by a set of `CREATE` statements.
47994836

48004837
The `ignore-failures` option can be set to `NONE` (the default), `DROPS` (ignore failed
4801-
drops) or `ALL` (ignore all failures).
4838+
drops), or `ALL` (ignore all failures).
48024839

48034840
If you need more control than you get from the XML namespace, you can simply use the
4804-
`DataSourceInitializer` directly, and define it as a component in your application.
4841+
`DataSourceInitializer` directly and define it as a component in your application.
48054842

48064843

48074844
[[jdbc-client-component-initialization]]
4808-
===== Initialization of Other Components that Depend on the Database
4845+
===== Initialization of other components that depend on the database
4846+
48094847
A large class of applications can just use the database initializer with no further
48104848
complications: those that do not use the database until after the Spring context has
4811-
started. If your application is __not__ one of those then you might need to read the
4812-
rest of this section.
4849+
started. If your application is __not__ one of those then you might need to read the rest
4850+
of this section.
48134851

4814-
The database initializer depends on a data source instance and runs the scripts provided
4815-
in its initialization callback (c.f. `init-method` in an XML bean definition or
4816-
`InitializingBean`). If other beans depend on the same data source and also use the data
4817-
source in an initialization callback then there might be a problem because the data has
4818-
not yet been initialized. A common example of this is a cache that initializes eagerly
4819-
and loads up data from the database on application startup.
4852+
The database initializer depends on a `DataSource` instance and executes the scripts
4853+
provided in its initialization callback (analogous to an `init-method` in an XML bean
4854+
definition, a `@PostConstruct` method in a component, or the `afterPropertiesSet()`
4855+
method in a component that implements `InitializingBean`). If other beans depend on the
4856+
same data source and also use the data source in an initialization callback, then there
4857+
might be a problem because the data has not yet been initialized. A common example of
4858+
this is a cache that initializes eagerly and loads data from the database on application
4859+
startup.
48204860

4821-
To get round this issue you two options: change your cache initialization strategy to a
4822-
later phase, or ensure that the database initializer is initialized first.
4861+
To get around this issue you have two options: change your cache initialization strategy
4862+
to a later phase, or ensure that the database initializer is initialized first.
48234863

48244864
The first option might be easy if the application is in your control, and not otherwise.
4825-
Some suggestions for how to implement this are
4865+
Some suggestions for how to implement this include:
48264866

4827-
* Make the cache initialize lazily on first usage, which improves application startup time
4867+
* Make the cache initialize lazily on first usage, which improves application startup
4868+
time.
48284869
* Have your cache or a separate component that initializes the cache implement
48294870
`Lifecycle` or `SmartLifecycle`. When the application context starts up a
48304871
`SmartLifecycle` can be automatically started if its `autoStartup` flag is set, and a
4831-
`Lifecycle` can be started manually by calling
4832-
`ConfigurableApplicationContext.start()` on the enclosing context.
4872+
`Lifecycle` can be started manually by calling `ConfigurableApplicationContext.start()`
4873+
on the enclosing context.
48334874
* Use a Spring `ApplicationEvent` or similar custom observer mechanism to trigger the
48344875
cache initialization. `ContextRefreshedEvent` is always published by the context when
48354876
it is ready for use (after all beans have been initialized), so that is often a useful
48364877
hook (this is how the `SmartLifecycle` works by default).
48374878

4838-
The second option can also be easy. Some suggestions on how to implement this are
4839-
4840-
* Rely on Spring BeanFactory default behavior, which is that beans are initialized in
4841-
registration order. You can easily arrange that by adopting the common practice of a
4842-
set of <import/> elements that order your application modules, and ensure that the
4843-
database and database initialization are listed first
4844-
* Separate the datasource and the business components that use it and control their
4845-
startup order by putting them in separate ApplicationContext instances (e.g. parent
4846-
has the datasource and child has the business components). This structure is common in
4847-
Spring web applications, but can be more generally applied.
4879+
The second option can also be easy. Some suggestions on how to implement this include:
4880+
4881+
* Rely on the default behavior of the Spring `BeanFactory`, which is that beans are
4882+
initialized in registration order. You can easily arrange that by adopting the common
4883+
practice of a set of `<import/>` elements in XML configuration that order your
4884+
application modules, and ensure that the database and database initialization are
4885+
listed first.
4886+
* Separate the `DataSource` and the business components that use it, and control their
4887+
startup order by putting them in separate `ApplicationContext` instances (e.g. the
4888+
parent context contains the `DataSource`, and child context contains the business
4889+
components). This structure is common in Spring web applications but can be more
4890+
generally applied.
48484891

48494892

48504893

0 commit comments

Comments
 (0)