提交 16c93910 编写于 作者: S Scott Andrews

SPR-5429 Update Pet Clinic to use HSQL as an embedded database

Created DbcpDataSourceFactory factory bean to create and populate a dbcp based connection pool.  The factory bean is based on EmbeddedDataSourceFactory from the JavaConfig version of Pet Clinic.  The new DbcpDataSourceFactory has been tested with HSQL in embedded and stand-alone modes.
上级 93352336
......@@ -7,6 +7,7 @@
@author Rob Harrop
@author Costin Leau
@author Sam Brannen
@author Scott Andrews
--------------------------------------------------------------------------------
......@@ -60,8 +61,13 @@ execution directory. Note that you must do this in order to execute the "tests"
target, as you need the JUnit task from Ant's optional.jar, which is not
included in this sample application.
To execute the web application with its default settings, simply start the
HSQLDB instance in the "db/hsqldb" directory, for example using "server.bat".
By default, an embedded HSQL instance in configured. No other steps are
necessary to get the data source up and running.
To use HSQL as a remote database, open "src/jdbc.properties", comment out all
properties in the "HSQL Embedded Settings" section, uncomment all properties in
the "HSQL Settings" section. Start the remote HSQLDB instance in the
"db/hsqldb" directory, for example using "server.bat".
For MySQL, you'll need to use the corresponding schema and SQL scripts in the
"db/mysql" subdirectory. Follow the steps outlined in
......
/*
* Copyright 2002-2008 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.samples.petclinic.config;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.io.Resource;
/**
* A factory that creates a data source fit for use in a system environment. Creates a DBCP simple data source
* from the provided connection properties.
*
* This factory returns a fully-initialized DataSource implementation. When the DataSource is returned, callers are
* guaranteed that the database schema and data will have been loaded by that time.
*
* Is a FactoryBean, for exposing the fully-initialized DataSource as a Spring bean. See {@link #getObject()}.
*
* @author Chris Beams
* @author Scott Andrews
*/
public class DbcpDataSourceFactory implements FactoryBean<DataSource>, DisposableBean {
// configurable properties
private String driverClassName;
private String url;
private String username;
private String password;
private boolean populate;
private Resource schemaLocation;
private Resource dataLocation;
/**
* The object created by this factory.
*/
private BasicDataSource dataSource;
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
/**
* The data source connection URL
*/
public void setUrl(String url) {
this.url = url;
}
/**
* The data source username
*/
public void setUsername(String username) {
this.username = username;
}
/**
*The data source password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Indicates that the data base should be populated from the schema and data locations
*/
public void setPopulate(boolean populate) {
this.populate = populate;
}
/**
* Sets the location of the file containing the schema DDL to export to the database.
* @param schemaLocation the location of the database schema DDL
*/
public void setSchemaLocation(Resource schemaLocation) {
this.schemaLocation = schemaLocation;
}
/**
* Sets the location of the file containing the data to load into the database.
* @param testDataLocation the location of the data file
*/
public void setDataLocation(Resource testDataLocation) {
this.dataLocation = testDataLocation;
}
// implementing FactoryBean
// this method is called by Spring to expose the DataSource as a bean
public DataSource getObject() throws Exception {
if (dataSource == null) {
initDataSource();
}
return dataSource;
}
public Class<DataSource> getObjectType() {
return DataSource.class;
}
public boolean isSingleton() {
return true;
}
// implementing DisposableBean
public void destroy() throws Exception {
dataSource.close();
}
// internal helper methods
// encapsulates the steps involved in initializing the data source: creating it, and populating it
private void initDataSource() {
// create the database source first
this.dataSource = createDataSource();
if (this.populate) {
// now populate the database by loading the schema and data
populateDataSource();
}
}
private BasicDataSource createDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(this.driverClassName);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password);
return dataSource;
}
private void populateDataSource() {
DatabasePopulator populator = new DatabasePopulator(dataSource);
populator.populate(this.schemaLocation);
populator.populate(this.dataLocation);
}
/**
* Populates a in memory data source with data.
*/
private class DatabasePopulator {
private DataSource dataSource;
/**
* Creates a new database populator.
* @param dataSource the data source that will be populated.
*/
public DatabasePopulator(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Populate the database executing the statements in the provided resource against the database
* @param sqlFile spring resource containing SQL to run against the db
*/
public void populate(Resource sqlFile) {
Connection connection = null;
try {
connection = dataSource.getConnection();
try {
String sql = parseSqlIn(sqlFile);
executeSql(sql, connection);
} catch (IOException e) {
throw new RuntimeException("I/O exception occurred accessing the database schema file", e);
} catch (SQLException e) {
throw new RuntimeException("SQL exception occurred exporting database schema", e);
}
} catch (SQLException e) {
throw new RuntimeException("SQL exception occurred acquiring connection", e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
}
}
}
}
// utility method to read a .sql txt input stream
private String parseSqlIn(Resource resource) throws IOException {
InputStream is = null;
try {
is = resource.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringWriter sw = new StringWriter();
BufferedWriter writer = new BufferedWriter(sw);
for (int c=reader.read(); c != -1; c=reader.read()) {
writer.write(c);
}
writer.flush();
return sw.toString();
} finally {
if (is != null) {
is.close();
}
}
}
// utility method to run the parsed sql
private void executeSql(String sql, Connection connection) throws SQLException {
Statement statement = connection.createStatement();
statement.execute(sql);
}
}
}
CREATE TABLE vets (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR(30)
);
CREATE INDEX vets_last_name ON vets(last_name);
CREATE TABLE specialties (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
name VARCHAR(80)
);
CREATE INDEX specialties_name ON specialties(name);
CREATE TABLE vet_specialties (
vet_id INTEGER NOT NULL,
specialty_id INTEGER NOT NULL
);
alter table vet_specialties add constraint fk_vet_specialties_vets foreign key (vet_id) references vets(id);
alter table vet_specialties add constraint fk_vet_specialties_specialties foreign key (specialty_id) references specialties(id);
CREATE TABLE types (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
name VARCHAR(80)
);
CREATE INDEX types_name ON types(name);
CREATE TABLE owners (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR(30),
address VARCHAR(255),
city VARCHAR(80),
telephone VARCHAR(20)
);
CREATE INDEX owners_last_name ON owners(last_name);
CREATE TABLE pets (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
name VARCHAR(30),
birth_date DATE,
type_id INTEGER NOT NULL,
owner_id INTEGER NOT NULL
);
alter table pets add constraint fk_pets_owners foreign key (owner_id) references owners(id);
alter table pets add constraint fk_pets_types foreign key (type_id) references types(id);
CREATE INDEX pets_name ON pets(name);
CREATE TABLE visits (
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
pet_id INTEGER NOT NULL,
visit_date DATE,
description VARCHAR(255)
);
alter table visits add constraint fk_visits_pets foreign key (pet_id) references pets(id);
CREATE INDEX visits_pet_id ON visits(pet_id);
INSERT INTO vets VALUES (1, 'James', 'Carter');
INSERT INTO vets VALUES (2, 'Helen', 'Leary');
INSERT INTO vets VALUES (3, 'Linda', 'Douglas');
INSERT INTO vets VALUES (4, 'Rafael', 'Ortega');
INSERT INTO vets VALUES (5, 'Henry', 'Stevens');
INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins');
INSERT INTO specialties VALUES (1, 'radiology');
INSERT INTO specialties VALUES (2, 'surgery');
INSERT INTO specialties VALUES (3, 'dentistry');
INSERT INTO vet_specialties VALUES (2, 1);
INSERT INTO vet_specialties VALUES (3, 2);
INSERT INTO vet_specialties VALUES (3, 3);
INSERT INTO vet_specialties VALUES (4, 2);
INSERT INTO vet_specialties VALUES (5, 1);
INSERT INTO types VALUES (1, 'cat');
INSERT INTO types VALUES (2, 'dog');
INSERT INTO types VALUES (3, 'lizard');
INSERT INTO types VALUES (4, 'snake');
INSERT INTO types VALUES (5, 'bird');
INSERT INTO types VALUES (6, 'hamster');
INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
INSERT INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
INSERT INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
INSERT INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
INSERT INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
INSERT INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
INSERT INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
INSERT INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
INSERT INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
INSERT INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
INSERT INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
INSERT INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
INSERT INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
INSERT INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
INSERT INTO visits VALUES (1, 7, '1996-03-04', 'rabies shot');
INSERT INTO visits VALUES (2, 8, '1996-03-04', 'rabies shot');
INSERT INTO visits VALUES (3, 8, '1996-06-04', 'neutered');
INSERT INTO visits VALUES (4, 7, '1996-09-04', 'spayed');
......@@ -12,13 +12,18 @@ hibernate.show_sql=true
jpa.showSql=true
#-------------------------------------------------------------------------------
# HSQL Settings
# HSQL Embedded Settings
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://localhost:9001
jdbc.url=jdbc:hsqldb:mem:petclinic
jdbc.username=sa
jdbc.password=
# Properties that control the population of schema and data for a new data source
jdbc.populate=true
jdbc.schemaLocation=classpath:/META-INF/hsqldb/initDB.txt
jdbc.dataLocation=classpath:/META-INF/hsqldb/populateDB.txt
# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
hibernate.dialect=org.hibernate.dialect.HSQLDialect
......@@ -29,6 +34,29 @@ jpa.databasePlatform=org.springframework.samples.petclinic.toplink.EssentialsHSQ
# Property that determines which database to use with an AbstractJpaVendorAdapter
jpa.database=HSQL
#-------------------------------------------------------------------------------
# HSQL Settings
#jdbc.driverClassName=org.hsqldb.jdbcDriver
#jdbc.url=jdbc:hsqldb:hsql://localhost:9001
#jdbc.username=sa
#jdbc.password=
# Properties that control the population of schema and data for a new data source
#jdbc.populate=false
#jdbc.schemaLocation=
#jdbc.dataLocation=
# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
#hibernate.dialect=org.hibernate.dialect.HSQLDialect
# Property that determines which JPA DatabasePlatform to use with TopLink Essentials
#jpa.databasePlatform=org.springframework.samples.petclinic.toplink.EssentialsHSQLPlatformWithNativeSequence
# Property that determines which database to use with an AbstractJpaVendorAdapter
#jpa.database=HSQL
#-------------------------------------------------------------------------------
# MySQL Settings
......@@ -37,6 +65,11 @@ jpa.database=HSQL
#jdbc.username=pc
#jdbc.password=pc
# Properties that control the population of schema and data for a new data source
#jdbc.populate=false
#jdbc.schemaLocation=
#jdbc.dataLocation=
# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
#hibernate.dialect=org.hibernate.dialect.MySQLDialect
......
......@@ -20,13 +20,17 @@
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
for the required JAR files. Alternatively you can use another connection pool
such as C3P0, similarly configured using Spring.
Spring FactoryBean that creates a DataSource using Apache Commons DBCP for connection
pooling. See Commons DBCP documentation for the required JAR files. This factory bean
can populate the data source with a schema and data scripts if configured to do so.
An alternate factory bean can be created for different connection pool implementations,
C3P0 for example.
-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<bean id="dataSource" class="org.springframework.samples.petclinic.config.DbcpDataSourceFactory"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
p:username="${jdbc.username}" p:password="${jdbc.password}" p:populate="${jdbc.populate}"
p:schemaLocation="${jdbc.schemaLocation}" p:dataLocation="${jdbc.dataLocation}"/>
<!-- JNDI DataSource for JEE environments -->
<!--
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册