RESOLVED - issue SPR-5917: DataSourceInitializer and namespace support for creating and populating databases

Moved populator to init package and added namespace features
This commit is contained in:
David Syer 2009-10-30 10:31:37 +00:00
parent ab403468f9
commit 0db68e1b57
24 changed files with 512 additions and 47 deletions

View File

@ -24,9 +24,9 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.embedded.DatabasePopulator;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
import org.springframework.jdbc.datasource.embedded.ResourceDatabasePopulator; import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element; import org.w3c.dom.Element;

View File

@ -0,0 +1,109 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses {@code initialize-database} element and
* creates a {@link BeanDefinition} for {@link DataSourceInitializer}. Picks up nested {@code script} elements and
* configures a {@link ResourceDatabasePopulator} for them.
@author Dave Syer
*
*/
public class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class);
builder.addPropertyReference("dataSource", element.getAttribute("data-source"));
builder.addPropertyValue("enabled", element.getAttribute("enabled"));
setDatabasePopulator(element, context, builder);
return getSourcedBeanDefinition(builder, element, context);
}
@Override
protected boolean shouldGenerateId() {
return true;
}
private void setDatabasePopulator(Element element, ParserContext context, BeanDefinitionBuilder builder) {
List<Element> scripts = DomUtils.getChildElementsByTagName(element, "script");
if (scripts.size() > 0) {
builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, context));
}
}
private DatabasePopulator createDatabasePopulator(Element element, List<Element> scripts, ParserContext context) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.setIgnoreFailedDrops(element.getAttribute("ignore-failures").equals("DROPS"));
populator.setContinueOnError(element.getAttribute("ignore-failures").equals("ALL"));
for (Element scriptElement : scripts) {
String location = scriptElement.getAttribute("location");
ResourceLoader resourceLoader = context.getReaderContext().getResourceLoader();
if (resourceLoader instanceof ResourcePatternResolver) {
try {
List<Resource> resources = new ArrayList<Resource>(Arrays.asList(((ResourcePatternResolver)resourceLoader).getResources(location)));
Collections.<Resource>sort(resources, new Comparator<Resource>() {
public int compare(Resource o1, Resource o2) {
try {
return o1.getURL().toString().compareTo(o2.getURL().toString());
} catch (IOException e) {
return 0;
}
}
});
for (Resource resource : resources) {
populator.addScript(resource);
}
} catch (IOException e) {
context.getReaderContext().error("Cannot locate resources for script from location="+location, scriptElement);
}
} else {
populator.addScript(resourceLoader.getResource(location));
}
}
return populator;
}
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
ParserContext context) {
AbstractBeanDefinition definition = builder.getBeanDefinition();
definition.setSource(context.extractSource(source));
return definition;
}
}

View File

@ -22,10 +22,12 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/** /**
* {@link NamespaceHandler} for JDBC configuration namespace. * {@link NamespaceHandler} for JDBC configuration namespace.
* @author Oliver Gierke * @author Oliver Gierke
* @author Dave Syer
*/ */
public class JdbcNamespaceHandler extends NamespaceHandlerSupport { public class JdbcNamespaceHandler extends NamespaceHandlerSupport {
public void init() { public void init() {
registerBeanDefinitionParser("embedded-database", new EmbeddedDatabaseBeanDefinitionParser()); registerBeanDefinitionParser("embedded-database", new EmbeddedDatabaseBeanDefinitionParser());
registerBeanDefinitionParser("initialize-database", new InitializeDatabaseBeanDefinitionParser());
} }
} }

View File

@ -19,6 +19,7 @@ package org.springframework.jdbc.datasource.embedded;
import org.springframework.core.io.ClassRelativeResourceLoader; import org.springframework.core.io.ClassRelativeResourceLoader;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
/** /**
* A builder that provides a fluent API for constructing an embedded database. * A builder that provides a fluent API for constructing an embedded database.

View File

@ -25,6 +25,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.jdbc.datasource.embedded; package org.springframework.jdbc.datasource.init;
import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.EncodedResource;

View File

@ -0,0 +1,76 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.datasource.init;
import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Used to populate a database during initialization.
* @author Dave Syer
* @since 3.0
* @see DatabasePopulator
*/
public class DataSourceInitializer implements InitializingBean {
private DataSource dataSource;
private DatabasePopulator databasePopulator;
private boolean enabled = true;
/**
* Flag to explicitly enable or disable the database populator.
*
* @param enabled true if the database populator will be called on startup
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* The {@link DatabasePopulator} to use to populate the data source. Mandatory with no default.
*
* @param databasePopulator the database populator to use.
*/
public void setDatabasePopulator(DatabasePopulator databasePopulator) {
this.databasePopulator = databasePopulator;
}
/**
* The {@link DataSource} to populate when this component is initialized. Mandatory with no default.
*
* @param dataSource the DataSource
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Use the populator to set up data in the data source. Both properties are mandatory with no defaults.
*
* @see InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (enabled) {
Assert.state(dataSource != null, "DataSource must be provided");
Assert.state(databasePopulator != null, "DatabasePopulator must be provided");
databasePopulator.populate(dataSource.getConnection());
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.jdbc.datasource.embedded; package org.springframework.jdbc.datasource.init;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.jdbc.datasource.embedded; package org.springframework.jdbc.datasource.init;
import java.io.IOException; import java.io.IOException;
import java.io.LineNumberReader; import java.io.LineNumberReader;
@ -28,7 +28,6 @@ import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource; import org.springframework.core.io.support.EncodedResource;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -40,6 +39,7 @@ import org.springframework.util.StringUtils;
* Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts.<br> * Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts.<br>
* *
* @author Keith Donald * @author Keith Donald
* @author Dave Syer
* @since 3.0 * @since 3.0
*/ */
public class ResourceDatabasePopulator implements DatabasePopulator { public class ResourceDatabasePopulator implements DatabasePopulator {
@ -50,6 +50,9 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
private String sqlScriptEncoding; private String sqlScriptEncoding;
private boolean ignoreFailedDrops = false;
private boolean continueOnError = false;
/** /**
* Add a script to execute to populate the database. * Add a script to execute to populate the database.
@ -67,6 +70,29 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
this.scripts = Arrays.asList(scripts); this.scripts = Arrays.asList(scripts);
} }
/**
* Flag to indicate that all failures in SQL should be logged but not cause a
* failure. Defaults to false.
*
* @param continueOnError the flag value to set
*/
public void setContinueOnError(boolean continueOnError) {
this.continueOnError = continueOnError;
}
/**
* Flag to indicate that a failed SQL <code>DROP</code> statement can be ignored.
* This is useful for non-embedded databases whose SQL dialect does not support
* an <code>IF EXISTS</code> clause in a <code>DROP</code>. The default is false
* so that if it the populator runs accidentally against an existing database it
* will fail fast when the script starts with a <code>DROP</code>.
*
* @param ignoreFailedDrops the flag value to set
*/
public void setIgnoreFailedDrops(boolean ignoreFailedDrops) {
this.ignoreFailedDrops = ignoreFailedDrops;
}
/** /**
* Specify the encoding for SQL scripts, if different from the platform encoding. * Specify the encoding for SQL scripts, if different from the platform encoding.
* Note setting this property has no effect on added scripts that are already * Note setting this property has no effect on added scripts that are already
@ -77,18 +103,16 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
this.sqlScriptEncoding = sqlScriptEncoding; this.sqlScriptEncoding = sqlScriptEncoding;
} }
public void populate(Connection connection) throws SQLException { public void populate(Connection connection) throws SQLException {
for (Resource script : this.scripts) { for (Resource script : this.scripts) {
executeSqlScript(connection, applyEncodingIfNecessary(script), false); executeSqlScript(connection, applyEncodingIfNecessary(script), continueOnError, ignoreFailedDrops);
} }
} }
private EncodedResource applyEncodingIfNecessary(Resource script) { private EncodedResource applyEncodingIfNecessary(Resource script) {
if (script instanceof EncodedResource) { if (script instanceof EncodedResource) {
return (EncodedResource) script; return (EncodedResource) script;
} } else {
else {
return new EncodedResource(script, this.sqlScriptEncoding); return new EncodedResource(script, this.sqlScriptEncoding);
} }
} }
@ -99,8 +123,9 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
* @param template the SimpleJdbcTemplate with which to perform JDBC operations * @param template the SimpleJdbcTemplate with which to perform JDBC operations
* @param resource the resource (potentially associated with a specific encoding) to load the SQL script from. * @param resource the resource (potentially associated with a specific encoding) to load the SQL script from.
* @param continueOnError whether or not to continue without throwing an exception in the event of an error. * @param continueOnError whether or not to continue without throwing an exception in the event of an error.
* @param ignoreFailedDrops whether of not to continue in thw event of specifically an error on a <code>DROP</code>.
*/ */
private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError) private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops)
throws SQLException { throws SQLException {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
@ -129,24 +154,21 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(rowsAffected + " rows affected by SQL: " + statement); logger.debug(rowsAffected + " rows affected by SQL: " + statement);
} }
} } catch (SQLException ex) {
catch (SQLException ex) { boolean dropStatement = statement.trim().toLowerCase().startsWith("drop");
if (continueOnError) { if (continueOnError || (dropStatement && ignoreFailedDrops)) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("Line " + lineNumber + " statement failed: " + statement, ex); logger.warn("Line " + lineNumber + " statement failed: " + statement, ex);
} }
} } else {
else {
throw ex; throw ex;
} }
} }
} }
} } finally {
finally {
try { try {
stmt.close(); stmt.close();
} } catch (Throwable ex) {
catch (Throwable ex) {
logger.debug("Could not close JDBC Statement", ex); logger.debug("Could not close JDBC Statement", ex);
} }
} }

View File

@ -1,18 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.org/schema/jdbc" <xsd:schema xmlns="http://www.springframework.org/schema/jdbc"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool" xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://www.springframework.org/schema/jdbc" targetNamespace="http://www.springframework.org/schema/jdbc"
elementFormDefault="qualified" elementFormDefault="qualified" attributeFormDefault="unqualified">
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"/> <xsd:import namespace="http://www.springframework.org/schema/beans"
<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-3.0.xsd"/> schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" />
<xsd:import namespace="http://www.springframework.org/schema/tool"
schemaLocation="http://www.springframework.org/schema/tool/spring-tool-3.0.xsd" />
<xsd:element name="embedded-database"> <xsd:element name="embedded-database">
<xsd:annotation> <xsd:annotation>
<xsd:documentation source="java:org.springframework.jdbc.embedded.EmbeddedDataSourceFactoryBean"><![CDATA[ <xsd:documentation
source="java:org.springframework.jdbc.embedded.EmbeddedDataSourceFactoryBean"><![CDATA[
Creates an embedded database instance and makes it available to other beans as a javax.sql.DataSource. Creates an embedded database instance and makes it available to other beans as a javax.sql.DataSource.
]]></xsd:documentation> ]]></xsd:documentation>
<xsd:appinfo> <xsd:appinfo>
@ -25,7 +26,8 @@
<xsd:complexContent> <xsd:complexContent>
<xsd:extension base="beans:identifiedType"> <xsd:extension base="beans:identifiedType">
<xsd:sequence> <xsd:sequence>
<xsd:element name="script" type="scriptType" minOccurs="0" maxOccurs="unbounded"> <xsd:element name="script" type="scriptType"
minOccurs="0" maxOccurs="unbounded">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
A SQL script to execute during embedded database initialization. A SQL script to execute during embedded database initialization.
@ -33,7 +35,8 @@
</xsd:annotation> </xsd:annotation>
</xsd:element> </xsd:element>
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="type" type="databaseType" default="HSQL"> <xsd:attribute name="type" type="databaseType"
default="HSQL">
<xsd:annotation> <xsd:annotation>
<xsd:documentation><![CDATA[ <xsd:documentation><![CDATA[
The type of embedded database to create, such as HSQL, H2 or Derby. Defaults to HSQL. The type of embedded database to create, such as HSQL, H2 or Derby. Defaults to HSQL.
@ -45,11 +48,90 @@
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="initialize-database">
<xsd:annotation>
<xsd:documentation
source="java:org.springframework.jdbc.embedded.DataSourceInitializer"><![CDATA[
Initializes a database instance with SQL scripts provided in nested <script/> elements.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="script" type="scriptType" minOccurs="1"
maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
A SQL script to execute during database initialization.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="data-source" type="xsd:string"
default="dataSource">
<xsd:annotation>
<xsd:documentation><![CDATA[
A reference to a data source that should be initialized. Defaults to "dataSource".
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref" />
<tool:expected-type type="javax.sql.DataSource" />
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="enabled" type="xsd:string" use="optional"
default="true">
<xsd:annotation>
<xsd:documentation>
Is this bean "enabled", that is, will the
scripts be executed?
Defaults to true, but can be used to switch on
and off the
initialization depending on the enviroment.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignore-failures" use="optional"
default="NONE">
<xsd:annotation>
<xsd:documentation>
Should failed SQL statements be ignored during initialization?
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="NONE">
<xsd:annotation>
<xsd:documentation><![CDATA[
Do not ignore failures (the default)
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="DROPS">
<xsd:annotation>
<xsd:documentation><![CDATA[
Ignore failed DROP statements
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="ALL">
<xsd:annotation>
<xsd:documentation><![CDATA[
Ignore all failures
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="scriptType"> <xsd:complexType name="scriptType">
<xsd:attribute name="location" type="xsd:string"> <xsd:attribute name="location" type="xsd:string">
<xsd:annotation> <xsd:annotation>
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[ <xsd:documentation><![CDATA[
The resource location of the SQL script to execute. The resource location of an SQL script to execute. Can be single script location or
a pattern (e.g. classpath:/com/foo/sql/*-data.sql).
]]></xsd:documentation> ]]></xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:attribute> </xsd:attribute>

View File

@ -0,0 +1,100 @@
package org.springframework.jdbc.config;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
public class InitializeDatabaseIntegrationTest {
private String enabled;
private ClassPathXmlApplicationContext context;
@Before
public void init() {
enabled = System.setProperty("ENABLED", "true");
}
@After
public void after() {
if (enabled != null) {
System.setProperty("ENABLED", enabled);
} else {
System.clearProperty("ENABLED");
}
if (context != null) {
context.close();
}
}
@Test
public void testCreateEmbeddedDatabase() throws Exception {
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-config.xml");
assertCorrectSetup(context.getBean("dataSource", DataSource.class));
}
@Test(expected = BadSqlGrammarException.class)
public void testDisableCreateEmbeddedDatabase() throws Exception {
System.setProperty("ENABLED", "false");
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-config.xml");
assertCorrectSetup(context.getBean("dataSource", DataSource.class));
}
@Test
public void testIgnoreFailedDrops() throws Exception {
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-fail-config.xml");
assertCorrectSetup(context.getBean("dataSource", DataSource.class));
}
@Test
public void testScriptNameWithPattern() throws Exception {
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-pattern-config.xml");
DataSource dataSource = context.getBean("dataSource", DataSource.class);
assertCorrectSetup(dataSource);
JdbcTemplate t = new JdbcTemplate(dataSource);
assertEquals("Dave", t.queryForObject("select name from T_TEST", String.class));
}
@Test
public void testCacheInitialization() throws Exception {
context = new ClassPathXmlApplicationContext("org/springframework/jdbc/config/jdbc-initialize-cache-config.xml");
assertCorrectSetup(context.getBean("dataSource", DataSource.class));
CacheData cache = context.getBean(CacheData.class);
assertEquals(1, cache.getCachedData().size());
}
private void assertCorrectSetup(DataSource dataSource) {
JdbcTemplate t = new JdbcTemplate(dataSource);
assertEquals(1, t.queryForInt("select count(*) from T_TEST"));
}
public static class CacheData implements InitializingBean {
private JdbcTemplate jdbcTemplate;
private List<Map<String,Object>> cache;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<Map<String,Object>> getCachedData() {
return cache;
}
public void afterPropertiesSet() throws Exception {
cache = jdbcTemplate.queryForList("SELECT * FROM T_TEST");
}
}
}

View File

@ -7,6 +7,7 @@ import static org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType.
import org.junit.Test; import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.CannotReadScriptException;
public class EmbeddedDatabaseBuilderTests { public class EmbeddedDatabaseBuilderTests {

View File

@ -8,6 +8,7 @@ import org.junit.Test;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
public class EmbeddedDatabaseFactoryBeanTests { public class EmbeddedDatabaseFactoryBeanTests {

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue;
import java.sql.Connection; import java.sql.Connection;
import org.junit.Test; import org.junit.Test;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
public class EmbeddedDatabaseFactoryTests { public class EmbeddedDatabaseFactoryTests {

View File

@ -0,0 +1 @@
drop table T_TEST;

View File

@ -0,0 +1 @@
update T_TEST set NAME='Dave' where name='Keith';

View File

@ -6,18 +6,18 @@
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-schema.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-test-data.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:embedded-database> </jdbc:embedded-database>
<jdbc:embedded-database id="h2DataSource" type="H2"> <jdbc:embedded-database id="h2DataSource" type="H2">
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-schema.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-test-data.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:embedded-database> </jdbc:embedded-database>
<jdbc:embedded-database id="derbyDataSource" type="DERBY"> <jdbc:embedded-database id="derbyDataSource" type="DERBY">
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-schema-derby.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-schema-derby.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/datasource/embedded/db-test-data.sql"/> <jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:embedded-database> </jdbc:embedded-database>
</beans> </beans>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<jdbc:embedded-database id="dataSource" type="HSQL"/>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:initialize-database>
<!-- This cache relies on data created in the initialize-database element. It works fine
if the bean definitions are registered in the right order. (Could possibly be fixed later.) -->
<bean class="org.springframework.jdbc.config.InitializeDatabaseIntegrationTest$CacheData">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<jdbc:embedded-database id="dataSource" type="HSQL"/>
<jdbc:initialize-database data-source="dataSource" enabled="#{systemProperties['ENABLED']}">
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:initialize-database>
</beans>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<jdbc:embedded-database id="dataSource" type="HSQL"/>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="classpath:org/springframework/jdbc/config/db-drops.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/config/db-test-data.sql"/>
</jdbc:initialize-database>
</beans>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<jdbc:embedded-database id="dataSource" type="HSQL"/>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:org/springframework/jdbc/config/db-schema.sql"/>
<jdbc:script location="classpath:org/springframework/jdbc/config/*-data.sql"/>
</jdbc:initialize-database>
</beans>