From aeee120431985106376dffb190769fb7e1ca1261 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Wed, 9 Sep 2009 17:28:21 +0000 Subject: [PATCH] Beverly's edits reviewed; fixed coverage for SimpleJdbcCall and the use of default parameter values (SPR-5929) --- spring-framework-reference/src/jdbc.xml | 2214 ++++++++++++----------- 1 file changed, 1167 insertions(+), 1047 deletions(-) diff --git a/spring-framework-reference/src/jdbc.xml b/spring-framework-reference/src/jdbc.xml index 152ec54cb2..c1209b254f 100644 --- a/spring-framework-reference/src/jdbc.xml +++ b/spring-framework-reference/src/jdbc.xml @@ -2,125 +2,190 @@ - Data access using JDBC + Data access with JDBC
- Introduction + Introduction to Spring Framework JDBC - The value-add provided by the Spring Framework's JDBC abstraction - framework is perhaps best shown by the following list (note that only the - italicized lines need to be coded by an application developer): + The value-add provided by the Spring Framework JDBC abstraction is + perhaps best shown by the sequence of actions outlined in the table + bellow. The table shows what actions Spring will take care of and which + actions are the responsibility of you, the application developer. - - - Define connection parameters - + + Spring JDBC - who does what? - - Open the connection - + + - - Specify the statement - + - - Prepare and execute the statement - + - - Set up the loop to iterate through the results (if any) - + + + Action - - Do the work for each iteration - + Spring - - Process any exception - + You + + - - Handle transactions - + + + Define connection parameters. - - Close the connection - - + - The Spring Framework takes care of all the grungy, low-level details - that can make JDBC such a tedious API to develop with. + X + + + + Open the connection. + + X + + + + + + Specify the SQL statement. + + + + X + + + + Declare parameters and provide parameter values + + + + X + + + + Prepare and execute the statement. + + X + + + + + + Set up the loop to iterate through the results (if + any). + + X + + + + + + Do the work for each iteration. + + + + X + + + + Process any exception. + + X + + + + + + Handle transactions. + + X + + + + + + Close the connection, statement and resultset. + + X + + + + + +
+ + The Spring Framework takes care of all the low-level details that + can make JDBC such a tedious API to develop with.
- Choosing a style - - There are a number of options for selecting an approach to form - the basis for your JDBC database access. There are three flavors of the - JdbcTemplate, a new "SimpleJdbc" approach taking advantage of database - metadata, and there is also the "RDBMS Object" style for a more object - oriented approach similar in style to the JDO Query design. We'll - briefly list the primary reasons why you would pick one of these - approaches. Keep in mind that even if you start using one of these - approaches, you can still mix and match if there is a feature in a - different approach that you would like to take advantage of. All - approaches requires a JDBC 2.0 compliant driver and some advanced - features require a JDBC 3.0 driver. + Choosing an approach for JDBC database access + + You can choose among several approaches to form the basis for your + JDBC database access. In addition to three flavors of the JdbcTemplate, + a new SimpleJdbcInsert and SimplejdbcCall approach optimizes database + metadata, and the RDBMS Object style takes a more object-oriented + approach similar to that of JDO Query design. Once you start using one + of these approaches, you can still mix and match to include a feature + from a different approach. All approaches require a JDBC 2.0-compliant + driver, and some advanced features require a JDBC 3.0 driver. + + + Spring 3.0 updates all of the following approaches with Java 5 + support such as generics and varargs. + - JdbcTemplate - this is the - classic Spring JDBC approach and the most widely used. This is the - "lowest level" approach and all other approaches use a JdbcTemplate - under the covers. In Spring 3.0 it has been updated with Java 5 - support like generics and varargs. + JdbcTemplate is the classic + Spring JDBC approach and the most popular. This "lowest level" + approach and all others use a JdbcTemplate under the covers, and all + are updated with Java 5 support such as generics and varargs. - NamedParameterJdbcTemplate - - wraps a JdbcTemplate to provide more convenient usage with named - parameters instead of the traditional JDBC "?" place holders. This + NamedParameterJdbcTemplate + wraps a JdbcTemplate to provide named parameters + instead of the traditional JDBC "?" placeholders. This approach provides better documentation and ease of use when you have multiple - parameters for an SQL statement. It has also been updated with Java - 5 support like generics and varargs for Spring 3.0. + parameters for an SQL statement. - SimpleJdbcTemplate - this - class combines the most frequently used operations across - JdbcTemplate and NamedParameterJdbcTemplate. It also adds some - additional convenience around support for Java 5 varargs where this - was not possible in the JdbcTemplate due to backwards compatibility - reasons. + SimpleJdbcTemplate combines + the most frequently used operations of JdbcTemplate and + NamedParameterJdbcTemplate. SimpleJdbcInsert and - SimpleJdbcCall - designed to take advantage of database - metadata to limit the amount of configuration needed. This will - simplify the coding to a point where you only need to provide the - name of the table or procedure and provide a Map of parameters - matching the column names. Designed to work together with the - SimpleJdbcTemplate. Requires a database that provides adequate - metadata. + SimpleJdbcCall optimize database metadata to limit the + amount of necessary configuration. This approach simplifies coding + so that you only need to provide the name of the table or procedure + and provide a map of parameters matching the column names. + This only works if the database provides adequate metadata. If the + database doesn't provide this metadata, you will have to provide + explicit configuration of the parameters. RDBMS Objects including MappingSqlQuery, - SqlUpdate and StoredProcedure - an approach where you - create reusable and thread safe objects during initialization of - your data access layer. This approach is modeled after JDO Query - where you define your query string, declare parameters and compile - the query. Once that is done any execute methods can be called - multiple times with various parameter values passed in. It has also - been updated with Java 5 support like generics and vararg support - for Spring 3.0. + SqlUpdate and StoredProcedure requires you to create + reusable and thread-safe objects during initialization of your data + access layer. This approach is modeled after JDO Query wherein you + define your query string, declare parameters, and compile the query. + Once you do that, execute methods can be called multiple times with + various parameter values passed in.
- The package hierarchy + Package hierarchy<!--I have provided links to main sections that deal with most packages. TR: OK--> The Spring Framework's JDBC abstraction framework consists of four different packages, namely core, @@ -129,129 +194,139 @@ The org.springframework.jdbc.core package contains the JdbcTemplate class and its various - callback interfaces, plus a variety of related classes. A sub-package + callback interfaces, plus a variety of related classes. A subpackage named org.springframework.jdbc.core.simple contains the SimpleJdbcTemplate class and the related SimpleJdbcInsert and - SimpleJdbcCall classes. Another sub-package named + SimpleJdbcCall classes. Another subpackage named org.springframework.jdbc.core.namedparam contains the NamedParameterJdbcTemplate class and the related - support classes. + support classes. See , , and The org.springframework.jdbc.datasource package contains a utility class for easy DataSource access, and various simple DataSource implementations that can be used for testing and running unmodified JDBC code outside of a Java EE - container. A sub-package named + container. A subpackage named org.springfamework.jdbc.datasource.embedded provides support for creating in-memory database instances using Java database - engines such as HSQL and H2. - - Next, the org.springframework.jdbc.object - package contains classes that represent RDBMS queries, updates, and - stored procedures as thread safe, reusable objects. This approach is - modeled by JDO, although of course objects returned by queries are - disconnected from the database. This higher level of JDBC - abstraction depends on the lower-level abstraction in the + engines such as HSQL and H2. See and + + + The org.springframework.jdbc.object package + contains classes that represent RDBMS queries, updates, and stored + procedures as thread safe, reusable objects. See .This approach is modeled by JDO, although of + course objects returned by queries are disconnected from + the database. This higher level of JDBC abstraction depends on the + lower-level abstraction in the org.springframework.jdbc.core package. - Finally the org.springframework.jdbc.support - package is where you find the SQLException - translation functionality and some utility classes. - - Exceptions thrown during JDBC processing are translated to - exceptions defined in the org.springframework.dao + The + org.springframework.jdbc.support package provides + SQLException translation functionality and some + utility classes. Exceptions thrown during JDBC processing are translated + to exceptions defined in the org.springframework.dao package. This means that code using the Spring JDBC abstraction layer does not need to implement JDBC or RDBMS-specific error handling. All - translated exceptions are unchecked giving you the option of catching - the exceptions that you can recover from while allowing other exceptions - to be propagated to the caller. + translated exceptions are unchecked, which gives you the option of + catching the exceptions from which you can recover while allowing other + exceptions to be propagated to the caller. See .
- Using the JDBC Core classes to control basic JDBC processing and - error handling + Using the JDBC core classes to control basic JDBC processing and + error handling<!--Note: I moved the *DataSource* subsection out of this section because it seems to belong more under *Controlling database connections.*--><!--This section here is about core classes, but datasource is a separate package from core. See *Package hierarchy* section above. TR: OK-->
<classname>JdbcTemplate</classname> The JdbcTemplate class is the central class - in the JDBC core package. It simplifies the use of JDBC since it handles - the creation and release of resources. This helps to avoid common errors - such as forgetting to always close the connection. It executes the core - JDBC workflow like statement creation and execution, leaving application - code to provide SQL and extract results. This class executes SQL - queries, update statements or stored procedure calls, imitating - iteration over ResultSets and extraction - of returned parameter values. It also catches JDBC exceptions and - translates them to the generic, more informative, exception hierarchy - defined in the org.springframework.dao - package. - - Code using the JdbcTemplate only need to - implement callback interfaces, giving them a clearly defined contract. - The PreparedStatementCreator callback + in the JDBC core package. It handles the creation and release of + resources, which helps you avoid common errors such as forgetting to + close the connection. It performs the basic tasks of the core JDBC + workflow such as statement creation and execution, leaving application + code to provide SQL and extract results. The + JdbcTemplate class executes SQL queries, update + statements and stored procedure calls, performs iteration over + ResultSets and extraction of returned + parameter values. + It also catches JDBC exceptions and translates them to the generic, more + informative, exception hierarchy defined in the + org.springframework.dao package. + + When you use the JdbcTemplate for your + code, you only need to implement callback interfaces, giving them a + clearly defined contract. The + PreparedStatementCreator callback interface creates a prepared statement given a Connection provided by this class, providing SQL and any necessary parameters. The same is true for the - CallableStatementCreator interface which - creates callable statement. The + CallableStatementCreator interface, which + creates callable statements. The RowCallbackHandler interface extracts values from each row of a ResultSet. + + The JdbcTemplate can be used within a DAO - implementation via direct instantiation with a + implementation through direct instantiation with a DataSource reference, or be configured in - a Spring IOC container and given to DAOs as a bean reference. Note: the - DataSource should always be configured as - a bean in the Spring IoC container, in the first case given to the - service directly, in the second case to the prepared template. + a Spring IoC container and given to DAOs as a bean reference. + The DataSource should always be + configured as a bean in the Spring IoC container. In the first case + the bean is given to the service directly; in the second case it is + given to the prepared template. + - Finally, all of the SQL issued by this class is logged at the - 'DEBUG' level under the category corresponding to the + All SQL issued by this class is logged at the + DEBUG level under the category corresponding to the fully qualified class name of the template instance (typically - JdbcTemplate, but it may be different if a custom - subclass of the JdbcTemplate class is being - used). + JdbcTemplate, but it may be different if you are + using a custom subclass of the JdbcTemplate + class).
- Examples + Examples of JdbcTemplate class usage - Find below some examples of using the - JdbcTemplate class. (These examples are not an - exhaustive list of all of the functionality exposed by the + This section provides some examples of + JdbcTemplate class usage. These examples are + not an exhaustive list of all of the functionality exposed by the JdbcTemplate; see the attendant Javadocs for - that). + that.
Querying (SELECT) - A simple query for getting the number of rows in a - relation. + Here is a simple query for getting the number of rows in a + relation: - + int rowCount = this.jdbcTemplate.queryForInt("select count(*) from t_actor"); - A simple query using a bind variable. + A simple query using a bind variable: - + int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt( + "select count(*) from t_actor where first_name = ?", "Joe"); - Querying for a String. + Querying for a String: - String lastName = this.jdbcTemplate.queryForObject( "select last_name from t_actor where id = ?", - new Object[]{1212L}, String.class);]]> + new Object[]{1212L}, String.class); Querying and populating a single domain - object. + object: - Actor actor = this.jdbcTemplate.queryForObject( "select first_name, last_name from t_actor where id = ?", new Object[]{1212L}, - new RowMapper() { + new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name")); @@ -259,13 +334,13 @@ return actor; } }); -]]> + - Querying and populating a number of domain objects. + Querying and populating a number of domain objects: - actors = this.jdbcTemplate.query( + List<Actor> actors = this.jdbcTemplate.query( "select first_name, last_name from t_actor", - new RowMapper() { + new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name")); @@ -273,21 +348,21 @@ return actor; } }); -]]> + If the last two snippets of code actually existed in the same application, it would make sense to remove the duplication present in the two RowMapper anonymous inner classes, and extract them out into a single class (typically a static inner class) that can then be referenced - by DAO methods as needed. For example, the last code snippet might - be better off written like so: + by DAO methods as needed. For example, it may be better to write the + last code snippet as follows: - findAllActors() { + public List<Actor> findAllActors() { return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper()); } -private static final class ActorMapper implements RowMapper { +private static final class ActorMapper implements RowMapper<Actor> { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); @@ -295,70 +370,74 @@ private static final class ActorMapper implements RowMapper { actor.setLastName(rs.getString("last_name")); return actor; } -}]]> +}
- Updating (INSERT/UPDATE/DELETE) + Updating (INSERT/UPDATE/DELETE) with jdbcTemplate<!--Provide introductory text as with other examples. TR: OK.--> - You use the update(..) method to + perform insert, update and delete operations. Parameter values are + usually provided as var args or alternatively as an object + array. + + this.jdbcTemplate.update( "insert into t_actor (first_name, last_name) values (?, ?)", - "Leonor", "Watling");]]> + "Leonor", "Watling"); - this.jdbcTemplate.update( "update t_actor set = ? where id = ?", - "Banjo", 5276L);]]> + "Banjo", 5276L); - this.jdbcTemplate.update( "delete from actor where id = ?", - Long.valueOf(actorId));]]> + Long.valueOf(actorId));
- Other operations + Other jdbcTemplate operations - The execute(..) method can be used to - execute any arbitrary SQL, and as such is often used for DDL - statements. It is heavily overloaded with variants taking callback - interfaces, binding variable arrays, and suchlike. + You can use the execute(..) method to + execute any arbitrary SQL, and as such the method is often used for + DDL statements. It is heavily overloaded with variants taking + callback interfaces, binding variable arrays, and so on. - + this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))"); - Invoking a simple stored procedure (more sophisticated stored - procedure support is covered - later). + The following example invokes a simple stored procedure. More + sophisticated stored procedure support is covered later. - this.jdbcTemplate.update( "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", - Long.valueOf(unionId));]]> + Long.valueOf(unionId));
- <classname>JdbcTemplate</classname> idioms (best - practices) + <classname>JdbcTemplate</classname> best practices Instances of the JdbcTemplate class are threadsafe once configured. This is important because it means that you can configure a single instance of a JdbcTemplate and then safely inject this shared reference into multiple DAOs (or - repositories). To be clear, the JdbcTemplate is - stateful, in that it maintains a reference to a + repositories). The JdbcTemplate is stateful, in + that it maintains a reference to a DataSource, but this state is not conversational state. - A common idiom when using the + A common practice when using the JdbcTemplate class (and the associated SimpleJdbcTemplate and NamedParameterJdbcTemplate classes) is to configure a DataSource - in your Spring configuration file, and then dependency inject that + in your Spring configuration file, and then dependency-inject that shared DataSource bean into your DAO classes; the JdbcTemplate is created in the setter for the DataSource. This leads - to DAOs that look in part like this: + to DAOs that look in part like the following: public class JdbcCorporateEventDao implements CorporateEventDao { @@ -373,42 +452,42 @@ private static final class ActorMapper implements RowMapper { The corresponding configuration might look like this. - -<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - - - + <bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao"> + <property name="dataSource" ref="dataSource"/> + </bean> - - - - - - + <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> + <property name="driverClassName" value="${jdbc.driverClassName}"/> + <property name="url" value="${jdbc.url}"/> + <property name="username" value="${jdbc.username}"/> + <property name="password" value="${jdbc.password}"/> + </bean> - + <context:property-placeholder location="jdbc.properties"/> -]]> +</beans> - An alternative to explicit configuration is to use the component - scanning and annotation support for dependency injection. In this case - we would annotate the setter method for the + An alternative to explicit configuration is to use + component-scanning and annotation support for dependency injection. In + this case you annotate the setter method for the DataSource with the - @Autowired annotation. + @Autowired annotation. public class JdbcCorporateEventDao implements CorporateEventDao { private JdbcTemplate jdbcTemplate; - @Autowired + @Autowired public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } @@ -416,52 +495,49 @@ private static final class ActorMapper implements RowMapper { // JDBC-backed implementations of the methods on the CorporateEventDao follow... } - The corresponding XML configuration file would look like the - following: + The corresponding XML configuration file would + look like the following: - -<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - - + <!-- Scans within the base package of the application for @Components to configure as beans --> + <context:component-scan base-package="org.springframework.docs.test" /> - - - - - - + <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> + <property name="driverClassName" value="${jdbc.driverClassName}"/> + <property name="url" value="${jdbc.url}"/> + <property name="username" value="${jdbc.username}"/> + <property name="password" value="${jdbc.password}"/> + </bean> - + <context:property-placeholder location="jdbc.properties"/> -]]>If you are using Spring's +</beans>If you are using Spring's JdbcDaoSupport class, and your various - JDBC-backed DAO classes extend from it, then you inherit a - setDataSource(..) method for free from said - superclass. It is totally up to you as to whether or not you inherit - from said class, you certainly are not forced to. If you look at the - source for the JdbcDaoSupport class you will - see that there is not a whole lot to it... it is provided as a + JDBC-backed DAO classes extend from it, then your sub-class inherits a + setDataSource(..) method from the + JdbcDaoSupport class. You + can choose whether to inherit from this class. The + JdbcDaoSupport class is provided as a convenience only. Regardless of which of the above template initialization styles - you choose to use (or not), there is (almost) certainly no need to - create a brand new instance of a JdbcTemplate - class each and every time you wish to execute some SQL... remember, - once configured, a JdbcTemplate instance is - threadsafe. A reason for wanting multiple - JdbcTemplate instances would be when you have - an application that accesses multiple databases, which requires - multiple DataSources, and subsequently - multiple differently configured - JdbcTemplates. + you choose to use (or not), it is seldom necessary to create a new + instance of a JdbcTemplate class each time you + want to execute SQL. Once configured, a + JdbcTemplate instance is threadsafe. You may + want multiple JdbcTemplate instances if your + application accesses multiple databases, which requires multiple + DataSources, and subsequently multiple + differently configured JdbcTemplates.
@@ -469,13 +545,13 @@ private static final class ActorMapper implements RowMapper { <classname>NamedParameterJdbcTemplate</classname> The NamedParameterJdbcTemplate class adds - support for programming JDBC statements using named parameters (as + support for programming JDBC statements using named parameters, as opposed to programming JDBC statements using only classic placeholder ('?') arguments. The NamedParameterJdbcTemplate class wraps a JdbcTemplate, and delegates to the wrapped JdbcTemplate to do much of its work. This section - will describe only those areas of the + describes only those areas of the NamedParameterJdbcTemplate class that differ from the JdbcTemplate itself; namely, programming JDBC statements using named parameters. @@ -497,18 +573,21 @@ public int countOfActorsByFirstName(String firstName) { } Notice the use of the named parameter notation in the value - assigned to the 'sql' variable, and the corresponding - value that is plugged into the 'namedParameters' + assigned to the sql variable, and the corresponding + value that is plugged into the namedParameters variable (of type MapSqlParameterSource). - If you like, you can also pass along named parameters (and their - corresponding values) to a - NamedParameterJdbcTemplate instance using the - (perhaps more familiar) Map-based style. - (The rest of the methods exposed by the - NamedParameterJdbcOperations - and + Alternatively, you can pass along named parameters and their + corresponding values to a + NamedParameterJdbcTemplate instance by using the + Map-based style.The + remaining methods exposed by the + NamedParameterJdbcOperations and implemented by the NamedParameterJdbcTemplate - class) follow a similar pattern and will not be covered here.) + class follow a similar pattern and are not covered here. + + The following example shows the use of the + Map-based style. // some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @@ -526,18 +605,17 @@ public int countOfActorsByFirstName(String firstName) { return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters); } - Another nice feature related to the + One nice feature related to the NamedParameterJdbcTemplate (and existing in the - same Java package) is the - SqlParameterSource interface. You have - already seen an example of an implementation of this interface in one of - the preceding code snippets (the - MapSqlParameterSource class). The entire point of - the SqlParameterSource is to serve as a - source of named parameter values to a + same Java package) is the SqlParameterSource + interface. You have already seen an example of an implementation of this + interface in one of the previous code snippet (the + MapSqlParameterSource class). An + SqlParameterSource is a source of + named parameter values to a NamedParameterJdbcTemplate. The MapSqlParameterSource class is a very simple - implementation, that is simply an adapter around a + implementation that is simply an adapter around a java.util.Map, where the keys are the parameter names and the values are the parameter values. @@ -594,50 +672,41 @@ public int countOfActors(Actor exampleActor) { NamedParameterJdbcTemplate class wraps a classic JdbcTemplate template; if you need access to the wrapped - JdbcTemplate instance (to access some of the - functionality only present in the JdbcTemplate - class), then you can use the - getJdbcOperations() method to access the - wrapped JdbcTemplate via the - JdbcOperations - interface. - - See also for some advice on how to best use - the NamedParameterJdbcTemplate class in the - context of an application. + JdbcTemplate instance to access functionality + only present in the JdbcTemplate class, you can + use the getJdbcOperations() method to access + the wrapped JdbcTemplate through the + JdbcOperations interface. + + See also for + guidelines on using the + NamedParameterJdbcTemplate class in the context + of an application.
<classname>SimpleJdbcTemplate</classname> + The SimpleJdbcTemplate class wraps the + classic JdbcTemplate and leverages Java 5 + language features such as varargs and autoboxing. + - The idea behind the - SimpleJdbcTemplate is to provide a simpler - interface that takes better advantage of Java 5 features. It was - initially the only JdbcOperations - implementation that provided support for Java 5 enhanced syntax with - generics and varargs. Now, in Spring 3.0, the original - JdbcTemplate has been upgraded to Java 5 as - well, but the SimpleJdbcTemplate still has the - advantage of providing a simpler API when you don't need access to all - the methods that the JdbcTemplate offers. Also, - since the SimpleJdbcTemplate was designed for - Java 5 there are more methods that take advantage of varargs due to - different ordering of the parameters. + In Spring 3.0, the original JdbcTemplate + also supports Java 5-enhanced syntax with generics and varargs. + However, the SimpleJdbcTemplate provides a + simpler API that works best when you do not need access to all the + methods that the JdbcTemplate offers. Also, because the + SimpleJdbcTemplate was designed for Java 5, it + has more methods that take advantage of varargs due to different + ordering of the parameters. - The SimpleJdbcTemplate class is a wrapper - around the classic JdbcTemplate that takes better - advantage of Java 5 language features such as varargs and - autoboxing. - The value-add of the SimpleJdbcTemplate class in the area of syntactic-sugar is best illustrated with a - 'before and after' example. The following code - snippet shows first some data access code using the classic - JdbcTemplate, followed immediately thereafter by - a code snippet that does the same job, only this time using the + before-and-after example. The next code snippet shows data access code + that uses the classic JdbcTemplate, followed by a + code snippet that does the same job with the SimpleJdbcTemplate. // classic JdbcTemplate-style... @@ -646,7 +715,7 @@ private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } - + public Actor findActor(String specialty, int age) { String sql = "select id, first_name, last_name from T_ACTOR" + @@ -664,11 +733,12 @@ public Actor findActor(String specialty, int age) { // notice the wrapping up of the argumenta in an array - return (Actor) jdbcTemplate.queryForObject(sql, new Object[] {id}, mapper); + return (Actor) jdbcTemplate.queryForObject(sql, new Object[] {specialty, age}, mapper); } - Here is the same method, only this time using the - SimpleJdbcTemplate. + Here is the same method, with the + SimpleJdbcTemplate. // SimpleJdbcTemplate-style... private SimpleJdbcTemplate simpleJdbcTemplate; @@ -696,9 +766,9 @@ public Actor findActor(String specialty, int age) { return this.simpleJdbcTemplate.queryForObject(sql, mapper, specialty, age); } - See also - for some advice on how to best use the SimpleJdbcTemplate - class in the context of an application. + See for guidelines on + how to use the SimpleJdbcTemplate class in the + context of an application. The SimpleJdbcTemplate class only offers @@ -708,105 +778,11 @@ public Actor findActor(String specialty, int age) { the SimpleJdbcTemplate, you can always access the underlying JdbcTemplate by calling the getJdbcOperations() method on the - SimpleJdbcTemplate, which will then allow you - to invoke the method that you want. The only downside is that the - methods on the JdbcOperations interface - are not generified, so you are back to casting and such again. - -
- -
- <interfacename>DataSource</interfacename> - - In order to work with data from a database, one needs to obtain a - connection to the database. The way Spring does this is through a - DataSource. A - DataSource is part of the JDBC - specification and can be seen as a generalized connection factory. It - allows a container or a framework to hide connection pooling and - transaction management issues from the application code. As a developer, - you don not need to know any details about how to connect to the - database, that is the responsibility for the administrator that sets up - the datasource. You will most likely have to fulfill both roles while - you are developing and testing you code though, but you will not - necessarily have to know how the production data source is - configured. - - When using Spring's JDBC layer, you can either obtain a data - source from JNDI or you can configure your own, using a connection pool - implementation provided by a third party. Popular ones are Apache - Jakarta Commons DBCP and C3P0. There are some implementations provided - in the Spring distribution, but they are only meant to be used for - testing purposes since they don't provide any pooling. - - We will use the DriverManagerDataSource - implementation for this section but there are several additional - implementations that will be covered later on. The - DriverManagerDataSource works the same way that - you probably are used to work when you obtain a JDBC connection. You - have to specify the fully qualified class name of the JDBC driver that - you are using so that the DriverManager can load - the driver class. Then you have to provide a URL that varies between - JDBC drivers. You have to consult the documentation for your driver for - the correct value to use here. Finally you must provide a username and a - password that will be used to connect to the database. Here is an - example of how to configure a - DriverManagerDataSource in Java code: - - - - We also have an example how this would look in an XML - configuration: - - - - - - - - -]]> - - - The DriverManagerDataSource class should - only be used for testing purposes since it does not provide pooling - and will perform poorly when multiple requests for a connection are - made. + SimpleJdbcTemplate, which then allows you to + invoke the method that you want. The only downside is that the methods + on the JdbcOperations interface are not + generic, so you are back to casting and so on. - - Just to provide a more complete picture we will also show the - configuration for DBCP and C3P0. We only show the basic connectivity - configuration here. There are more options documented in the product - documentation for the respective connection pooling implementations that - will help control the pooling features. - - FIrst we have the DBCP configuration: - - - - - - - - -]]> - - And last we have the C3P0 configuration: - - - - - - - - -]]>
@@ -815,53 +791,81 @@ dataSource.setPassword("");]]> SQLExceptionTranslator is an interface to be implemented by classes that can translate between SQLExceptions and Spring's own - data-access-strategy-agnostic - org.springframework.dao.DataAccessException. - Implementations can be generic (for example, using SQLState codes for - JDBC) or proprietary (for example, using Oracle error codes) for greater - precision. + org.springframework.dao.DataAccessException, + which is agnostic in regard to data access strategy. Implementations can + be generic (for example, using SQLState codes for JDBC) or proprietary + (for example, using Oracle error codes) for greater precision. SQLErrorCodeSQLExceptionTranslator is the implementation of SQLExceptionTranslator that is used by default. This implementation uses specific vendor codes. - More precise than SQLState implementation, but vendor - specific. The error code translations are based on codes held in a - JavaBean type class named SQLErrorCodes. This - class is created and populated by an - SQLErrorCodesFactory which as the name suggests - is a factory for creating SQLErrorCodes based on - the contents of a configuration file named 'sql-error-codes.xml'. This file is - populated with vendor codes and based on the DatabaseProductName taken - from the DatabaseMetaData, the codes for - the current database are used. + It is more precise than the SQLState implementation. + The error code translations are based on codes held in a JavaBean type + class called SQLErrorCodes. This class is created + and populated by an SQLErrorCodesFactory which as + the name suggests is a factory for creating + SQLErrorCodes based on the contents of a + configuration file named sql-error-codes.xml. This file is + populated with vendor codes and based on the + DatabaseProductName taken from the + DatabaseMetaData. The codes for the acual + database you are using are used. The SQLErrorCodeSQLExceptionTranslator - applies the following matching rules: + applies matching rules in the following sequence: + + The SQLErrorCodesFactory is used by + default to define Error codes and custom exception translations. + They are looked up in a file named + sql-error-codes.xml from the classpath and + the matching SQLErrorCodes instance is + located based on the database name from the database metadata of + the database in use. + + - Try custom translation implemented by any subclass. Note - that this class is concrete and is typically used itself, in which - case this rule does not apply. + Any a custom translation implemented by a subclass. Normally + the provided concrete + SQLErrorCodeSQLExceptionTranslator is used + so this rule does not apply. It only applies if you have actually + provided a subclass implementation. - Apply error code matching. Error codes are obtained from the - SQLErrorCodesFactory by default. This looks - up error codes from the classpath and keys into them from the - database name from the database metadata. + Any custom implementation of the + SQLExceptionTranslator interface that is + provided as the + customSqlExceptionTranslator property of + the SQLErrorCodes class. + + + + The list of instances of the + CustomSQLErrorCodesTranslation class, + provided for the customTranslations + property of the SQLErrorCodes class, are + searched for a match. + + + + Error code matching is applied. Use the fallback translator. - SQLStateSQLExceptionTranslator is the - default fallback translator. + SQLExceptionSubclassTranslator is the + default fallback translator. If this translation is not available + then the next fallback translator is the + SQLStateSQLExceptionTranslator. - + - SQLErrorCodeSQLExceptionTranslator can be - extended the following way: + You can extend + SQLErrorCodeSQLExceptionTranslator: - public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator { protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) { if (sqlex.getErrorCode() == -12345) { @@ -869,14 +873,13 @@ dataSource.setPassword("");]]> } return null; } -}]]> - - In this example the specific error code - '-12345' is translated and any other errors are - simply left to be translated by the default translator implementation. - To use this custom translator, it is necessary to pass it to the - JdbcTemplate using the method - setExceptionTranslator and to use this +} + + In this example, the specific error code -12345 + is translated and other errors are left to be translated by the default + translator implementation. To use this custom translator, it is + necessary to pass it to the JdbcTemplate through + the method setExceptionTranslator and to use this JdbcTemplate for all of the data access processing where this translator is needed. Here is an example of how this custom translator can be used: @@ -902,23 +905,22 @@ public void setDataSource(DataSource dataSource) { pct, orderId); } - The custom translator is passed a data source because we still - want the default translation to look up the error codes in - sql-error-codes.xml. + The custom translator is passed a data source in order to look up + the error codes in sql-error-codes.xml.
Executing statements - To execute an SQL statement, there is very little code needed. All - you need is a DataSource and a - JdbcTemplate. Once you have that, you can use a - number of convenience methods that are provided with the - JdbcTemplate. Here is a short example showing - what you need to include for a minimal but fully functional class that - creates a new table. + Executing an SQL statement requires very little code. You need a + DataSource and a + JdbcTemplate, including the convenience + methods + that are provided with the JdbcTemplate. The + following example shows what you need to include for a minimal but fully + functional class that creates a new table: - import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; public class ExecuteAStatement { @@ -932,27 +934,25 @@ public class ExecuteAStatement { public void doExecute() { this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))"); } -}]]> +}
- Running Queries + Running queries - In addition to the execute methods, there is a large number of - query methods. Some of these methods are intended to be used for queries - that return a single value. Maybe you want to retrieve a count or a - specific value from one row. If that is the case then you can use + Some query methods return a single value. To retrieve a count or a + specific value from one row, use queryForInt(..), queryForLong(..) or - queryForObject(..). The latter will convert the + queryForObject(..). The latter converts the returned JDBC Type to the Java class that is passed in as an argument. If the type conversion is invalid, then an - InvalidDataAccessApiUsageException will - be thrown. Here is an example that contains two query methods, one for - an int and one that queries for a + InvalidDataAccessApiUsageException is + thrown. Here is an example that contains two query methods, one for an + int and one that queries for a String. - import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; public class RunAQuery { @@ -974,46 +974,43 @@ public class RunAQuery { public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } -}]]> +} - In addition to the single results query methods there are several - methods that return a List with an entry for each row that the query - returned. The most generic method is - queryForList(..) which returns a - List where each entry is a + In addition to the single result query methods, several methods + return a list with an entry for each row that the query returned. The + most generic method is queryForList(..) which + returns a List where each entry is a Map with each entry in the map - representing the column value for that row. If we add a method to the + representing the column value for that row. If you add a method to the above example to retrieve a list of all the rows, it would look like this: - private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } -public List> getList() { +public List<Map<String, Object>> getList() { return this.jdbcTemplate.queryForList("select * from mytable"); -}]]> +} The list returned would look something like this: - + [{name=Bob, id=1}, {name=Mary, id=2}]
Updating the database - There are also a number of update methods that you can use. Find - below an example where a column is updated for a certain primary key. In - this example an SQL statement is used that has place holders for row - parameters. Note that the parameter values can be passed in as varargs - or alternatively as an array of objects (and thus primitives should - either be wrapped in the primitive wrapper classes either explicitly or - using auto-boxing). + The following example shows a column updated for a certain primary + key. In this example, an SQL statement has placeholders for row + parameters. The parameter values can be passed in as varargs or + alternatively as an array of objects. Thus primitives should be wrapped + in the primitive wrapper classes explicitly or using auto-boxing. - import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; @@ -1030,24 +1027,24 @@ public class ExecuteAnUpdate { "update mytable set name = ? where id = ?", name, id); } -}]]> +}
Retrieving auto-generated keys - One of the update convenience methods - provides support for acquiring the primary keys generated by the - database (part of the JDBC 3.0 standard - see chapter 13.6 of the - specification for details). The method takes a + An update convenience method supports the retrieval of primary keys generated + by the database. This support is part of the JDBC 3.0 standard; see + Chapter 13.6 of the specification for details. The method takes a PreparedStatementCreator as its first argument, and this is the way the required insert statement is specified. The - other argument is a KeyHolder, which will contain - the generated key on successful return from the update. There is not a + other argument is a KeyHolder, which contains the + generated key on successful return from the update. There is not a standard single way to create an appropriate PreparedStatement (which explains why the method - signature is the way it is). An example that works on Oracle and may not - work on other platforms is: + signature is the way it is). The following example works on Oracle but + may not work on other platforms: final String INSERT_SQL = "insert into my_test (name) values(?)"; final String name = "Rob"; @@ -1071,36 +1068,126 @@ jdbcTemplate.update(
Controlling database connections +
+ <interfacename>DataSource</interfacename><!--I don't understand why *DataSource* was a subsection of *Using the JDBC classes to control basic JDBC processing and error handling*.--><!--According to *The package hierarchy*section, there is a datasource package, separate from the core package.So I moved it to this section. TR: OK.--> + + Spring obtains a connection to the database through a + DataSource. A + DataSource is part of the JDBC + specification and is a generalized connection factory. It allows a + container or a framework to hide connection pooling and transaction + management issues from the application code. As a developer, you need + not know details about how to connect to the database; that is the + responsibility of the administrator that sets up the datasource. You + most likely fill both roles as you develop and test code, but you do not + necessarily have to know how the production data source is + configured. + + When using Spring's JDBC layer, you obtain a data source from JNDI + or you configure your own with a connection pool implementation provided + by a third party. Popular implementations are Apache Jakarta Commons + DBCP and C3P0. Implementations in the Spring distribution are meant only + for testing purposes and do not provide pooling. + + This section uses Spring's + DriverManagerDataSource implementation, and + several additional implementations are covered later. + + + Only use the DriverManagerDataSource + class should only be used for testing purposes since it does not + provide pooling and will perform poorly when multiple requests for a + connection are made. + You obtain a connection with + DriverManagerDataSource as you typically obtain a + JDBC connection. Specify the fully qualified classname of the JDBC + driver so that the DriverManager can load the + driver class. Next, provide a URL that varies between JDBC drivers. + (Consult the documentation for your driver for the correct value.) Then + provide a username and a password to connect to the database. Here is an + example of how to configure a + DriverManagerDataSource in Java code: + + DriverManagerDataSource dataSource = new DriverManagerDataSource(); +dataSource.setDriverClassName("org.hsqldb.jdbcDriver"); +dataSource.setUrl("jdbc:hsqldb:hsql://localhost:"); +dataSource.setUsername("sa"); +dataSource.setPassword(""); + + Here is the corresponding XML configuration: + + <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> + <property name="driverClassName" value="${jdbc.driverClassName}"/> + <property name="url" value="${jdbc.url}"/> + <property name="username" value="${jdbc.username}"/> + <property name="password" value="${jdbc.password}"/> +</bean> + +<context:property-placeholder location="jdbc.properties"/> + + The following examples show the basic connectivity and + configuration for DBCP and C3P0. To learn about more options that help + control the pooling features, see the product documentation for the + respective connection pooling implementations. + + DBCP configuration: + + <bean id="dataSource" + class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> + <property name="driverClassName" value="${jdbc.driverClassName}"/> + <property name="url" value="${jdbc.url}"/> + <property name="username" value="${jdbc.username}"/> + <property name="password" value="${jdbc.password}"/> +</bean> + +<context:property-placeholder location="jdbc.properties"/> + + C3P0 configuration: + + <bean id="dataSource" + class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> + <property name="driverClass" value="${jdbc.driverClassName}"/> + <property name="jdbcUrl" value="${jdbc.url}"/> + <property name="user" value="${jdbc.username}"/> + <property name="password" value="${jdbc.password}"/> +</bean> + +<context:property-placeholder location="jdbc.properties"/> +
+
<classname>DataSourceUtils</classname> The DataSourceUtils class is a convenient and powerful helper class that provides static methods to obtain connections from JNDI and close connections if - necessary. It has support for thread-bound connections, for example for - use with DataSourceTransactionManager. + necessary. It supports thread-bound connections with, for example, + DataSourceTransactionManager.
<interfacename>SmartDataSource</interfacename> - The SmartDataSource interface is to - be implemented by classes that can provide a connection to a relational - database. Extends the DataSource - interface to allow classes using it to query whether or not the - connection should be closed after a given operation. This can sometimes - be useful for efficiency, in the cases where one knows that one wants to - reuse a connection. + The SmartDataSource interface + should be implemented by classes that can provide a connection to a + relational database. It extends the + DataSource interface to allow classes + using it to query whether the connection should be closed after a given + operation. This usage is efficient when you know that you will reuse a + connection.
<classname>AbstractDataSource</classname> - This is an abstract base class for Spring's - DataSource implementations, that takes - care of the "uninteresting" glue. This is the class one would extend if - one was writing one's own DataSource - implementation. + AbstractDataSource is an + abstract base class for + Spring's DataSource implementations that + implements code that is common to all DataSource + implementations. + You extend the AbstractDataSource class if you + are writing your own DataSource + implementation.
@@ -1110,15 +1197,17 @@ jdbcTemplate.update( implementation of the SmartDataSource interface that wraps a single Connection that is - not closed after use. Obviously, this is not + not closed after each use. Obviously, this is not multi-threading capable. - If client code will call close in the assumption of a pooled - connection, like when using persistence tools, set - suppressClose to true. This will - return a close-suppressing proxy instead of the physical connection. Be - aware that you will not be able to cast this to a native Oracle - Connection or the like anymore. + If any client code calls close in the + assumption of a pooled connection, as when using persistence tools, set + the suppressClose property to + true. This + setting returns a close-suppressing proxy wrapping the physical + connection. Be aware that you will not be able to cast this + to a native Oracle Connection or the like + anymore. This is primarily a test class. For example, it enables easy testing of code outside an application server, in conjunction with a @@ -1133,20 +1222,20 @@ jdbcTemplate.update( The DriverManagerDataSource class is an implementation of the standard DataSource - interface that configures a plain old JDBC Driver via bean properties, + interface that configures a plain JDBC driver through bean properties, and returns a new Connection every time. - This is potentially useful for test or standalone environments - outside of a Java EE container, either as a + This implementation is useful for test and stand-alone + environments outside of a Java EE container, either as a DataSource bean in a Spring IoC container, or in conjunction with a simple JNDI environment. Pool-assuming Connection.close() calls will simply close the connection, so any DataSource-aware persistence code should - work. However, using JavaBean style connection pools such as - commons-dbcp is so easy, even in a test environment, that it is almost - always preferable to use such a connection pool over + work. However, using JavaBean-style connection pools such as + commons-dbcp is so easy, even in a test environment, that + it is almost always preferable to use such a connection pool over DriverManagerDataSource.
@@ -1156,17 +1245,18 @@ jdbcTemplate.update( TransactionAwareDataSourceProxy is a proxy for a target DataSource, which wraps that target DataSource to add awareness of - Spring-managed transactions. In this respect it is similar to a + Spring-managed transactions. In this respect, it is similar to a transactional JNDI DataSource as provided by a Java EE server. - It should almost never be necessary or desirable to use this - class, except when existing code exists which must be called and - passed a standard JDBC DataSource - interface implementation. In this case, it's possible to still have - this code be usable, but participating in Spring managed transactions. - It is generally preferable to write your own new code using the higher + It is rarely desirable to use this class, except when already + existing code that must be called and passed a standard JDBC + DataSource interface implementation. In + this case, it's possible to still have this code be usable, and at the + same time have this code participating in Spring managed transactions. + It + is generally preferable to write your own new code using the higher level abstractions for resource management, such as JdbcTemplate or DataSourceUtils. @@ -1186,37 +1276,38 @@ jdbcTemplate.update( specified data source to the currently executing thread, potentially allowing for one thread connection per data source. - Application code is required to retrieve the JDBC connection via + Application code is required to + retrieve the JDBC connection through DataSourceUtils.getConnection(DataSource) instead of - Java EE's standard DataSource.getConnection. This is - recommended anyway, as it throws unchecked - org.springframework.dao exceptions instead of checked - SQLExceptions. All framework classes like - JdbcTemplate use this strategy implicitly. If not - used with this transaction manager, the lookup strategy behaves exactly - like the common one - it can thus be used in any case. + Java EE's standard DataSource.getConnection. It + throws unchecked org.springframework.dao exceptions + instead of checked SQLExceptions. All + framework classes like JdbcTemplate use this + strategy implicitly. If not used with this transaction manager, the + lookup strategy behaves exactly like the common one - it can thus be + used in any case. The DataSourceTransactionManager class supports custom isolation levels, and timeouts that get applied as appropriate JDBC statement query timeouts. To support the latter, application code must either use JdbcTemplate or - call DataSourceUtils.applyTransactionTimeout(..) + call the DataSourceUtils.applyTransactionTimeout(..) method for each created statement. This implementation can be used instead of JtaTransactionManager in the single resource case, as it does not require the container to support JTA. Switching between both is just a matter of configuration, if you stick to the - required connection lookup pattern. Note that JTA does not support - custom isolation levels! + required connection lookup pattern. JTA does not support custom + isolation levels!
NativeJdbcExtractor - There are times when we need to access vendor specific JDBC - methods that differ from the standard JDBC API. This can be problematic - if we are running in an application server or with a + Sometimes you need to access vendor specific JDBC methods that + differ from the standard JDBC API. This can be problematic if you are + running in an application server or with a DataSource that wraps the Connection, Statement and ResultSet objects with its own wrapper objects. @@ -1225,8 +1316,8 @@ jdbcTemplate.update( OracleLobHandler with a NativeJdbcExtractor. - The NativeJdbcExtractor comes in a variety of flavors to match - your execution environment: + The NativeJdbcExtractor comes in a variety of flavors + to match your execution environment: @@ -1260,7 +1351,7 @@ jdbcTemplate.update( Usually the SimpleNativeJdbcExtractor is sufficient for unwrapping a Connection object in - most environments. See the Java Docs for more details. + most environments. See the Javadocs for more details.
@@ -1269,35 +1360,34 @@ jdbcTemplate.update( Most JDBC drivers provide improved performance if you batch multiple calls to the same prepared statement. By grouping updates into batches you - limit the number of round trips to the database. This section will cover - batch processing using both the JdbcTemplate and the - SimpleJdbcTemplate. + limit the number of round trips to the database. This section covers batch + processing using both the JdbcTemplate and the + SimpleJdbcTemplate.
Batch operations with the JdbcTemplate - Using the JdbcTemplate batch processing is accomplished by - implementing a special interface, + You accomplish JdbcTemplate batch + processing by implementing two methods of a special interface, BatchPreparedStatementSetter, and passing that in as the second parameter in your batchUpdate - method call. This interface has two methods you must implement. One is - named getBatchSize and here you provide the size - of the current batch. The other method is - setValues and it allows you to set the values for - the parameters of the prepared statement and. This method will get - called the number of times that you specified in the - getBatchSize call. Here is an example of this - where we update the actor table based on entries in a list. The entire - list is used as the batch in his example. - - getBatchSize method to + provide the size of the current batch. Use the + setValues method to set the values for the + parameters of the prepared statement. This method will be called the + number of times that you specified in the + getBatchSize call. The following example updates + the actor table based on entries in a list. The entire list is used as + the batch in this example: + + public class JdbcActorDao implements ActorDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } - public int[] batchUpdate(final List actors) { + public int[] batchUpdate(final List<Actor> actors) { int[] updateCounts = jdbcTemplate.batchUpdate( "update t_actor set first_name = ?, last_name = ? where id = ?", new BatchPreparedStatementSetter() { @@ -1315,13 +1405,13 @@ jdbcTemplate.update( } // ... additional methods -}]]>If you are processing stream of updates or reading from a - file then you might have a preferred batch size, but the last batch +}If you are processing a stream of updates or reading from a + file, then you might have a preferred batch size, but the last batch might not have that number of entries. In this case you can use the InterruptibleBatchPreparedStatementSetter - interface which allows you to interrupt a batch once the input source is - exhausted. The isBatchExhausted method allows you - to signal the end of the batch. + interface, which allows you to interrupt a batch once the input source + is exhausted. The isBatchExhausted method allows + you to signal the end of the batch.
@@ -1329,26 +1419,26 @@ jdbcTemplate.update( The SimpleJdbcTemplate provides an alternate way of providing the batch update. Instead of implementing a - special batch interface, you simply provide all parameter values in the - call and the framework will loop over these values and use an internal - prepared statement setter. The API varies depending on whether you use - named parameters or not. For the named parameters you provide an array - of SqlParameterSource, one entry for each member - of the batch. You can use the + special batch interface, you provide all parameter values in the call. + The framework loops over these values and uses an internal prepared + statement setter. The API varies depending on whether you use named + parameters. For the named parameters you provide an array of + SqlParameterSource, one entry for each member of + the batch. You can use the SqlParameterSource.createBatch method to create this array, passing in either an array of JavaBeans or an array of Maps containing the parameter values. This example shows a batch update using named parameters: - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); } - public int[] batchUpdate(final List actors) { + public int[] batchUpdate(final List<Actor> actors) { SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray()); int[] updateCounts = simpleJdbcTemplate.batchUpdate( "update t_actor set first_name = :firstName, last_name = :lastName where id = :id", @@ -1357,23 +1447,23 @@ jdbcTemplate.update( } // ... additional methods -}]]>For an SQL statement using the classic "?" place holders - you pass in a List containing an object array with the update values. - This object array must have one entry for each placeholder in the SQL - statement and they must be in the same order as they are defined in the +}For an SQL statement using the classic "?" placeholders, you + pass in a list containing an object array with the update values. This + object array must have one entry for each placeholder in the SQL + statement, and they must be in the same order as they are defined in the SQL statement. - The same example using classic JDBC "?" place holders: + The same example using classic JDBC "?" placeholders: - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); } - public int[] batchUpdate(final List actors) { - List batch = new ArrayList(); + public int[] batchUpdate(final List<Actor> actors) { + List<Object[]> batch = new ArrayList<Object[]>(); for (Actor actor : actors) { Object[] values = new Object[] { actor.getFirstName(), @@ -1388,10 +1478,10 @@ jdbcTemplate.update( } // ... additional methods -}]]>All batch update methods return an int array containing - the number of affected rows for each batch entry. This count is reported - by the JDBC driver and it's not always available in which case the JDBC - driver simply returns a -2 value. +}All batch update methods return an int array containing the + number of affected rows for each batch entry. This count is reported by + the JDBC driver. If the count is not available, the JDBC driver returns + a -2 value.
@@ -1399,30 +1489,31 @@ jdbcTemplate.update( Simplifying JDBC operations with the SimpleJdbc classes The SimpleJdbcInsert and - SimpleJdbcCall classes provide simplified + SimpleJdbcCall classes provide a simplified configuration by taking advantage of database metadata that can be - retrieved via the JDBC driver. This means there is less to configure up - front, although you can override or turn off the metadata processing if + retrieved through the JDBC driver. This means there is less to configure + up front, although you can override or turn off the metadata processing if you prefer to provide all the details in your code.
Inserting data using SimpleJdbcInsert Let's start by looking at the - SimpleJdbcInsert class first. We will use the - minimal amount of configuration options to start with. The - SimpleJdbcInsert should be instantiated in the - data access layer's initialization method. For this example, the - initializing method is the setDataSource method. - There is no need to subclass the SimpleJdbcInsert - class, just create a new instance and set the table name using the + SimpleJdbcInsert class with the minimal amount of + configuration options. You should instantiate the + SimpleJdbcInsert in the data access layer's + initialization method. For this example, the initializing method is the + setDataSource method. You do not need to subclass + the SimpleJdbcInsert class; simply create a new + instance and set the table name using the withTableName method. Configuration methods for - this class follows the "fluid" style returning the instance of the - SimpleJdbcInsert which allows you to chain all - configuration methods. In this case there is only one configuration - method used but we will see examples of multiple ones soon. + this class follow the "fluid" style that returns the instance of the + SimpleJdbcInsert, which allows you to chain all + configuration methods. This example uses only one configuration method; + you will see examples of multiple ones later. - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; @@ -1433,7 +1524,7 @@ jdbcTemplate.update( } public void add(Actor actor) { - Map parameters = new HashMap(3); + Map<String, Object> parameters = new HashMap<String, Object>(3); parameters.put("id", actor.getId()); parameters.put("first_name", actor.getFirstName()); parameters.put("last_name", actor.getLastName()); @@ -1441,7 +1532,7 @@ jdbcTemplate.update( } // ... additional methods -}]]> +} The execute method used here takes a plain java.utils.Map as its only parameter. The @@ -1454,14 +1545,14 @@ jdbcTemplate.update(
Retrieving auto-generated keys using SimpleJdbcInsert - Next we'll look at the same insert, but instead of passing in the - id we will retrieve the auto-generated key and set it on the new Actor - object. When we create the SimpleJdbcInsert, in - addition to specifying the table name, we specify the name of the - generated key column using the + This example uses the same insert as the preceding, but instead of + passing in the id it retrieves the auto-generated key and sets it on the + new Actor object. When you create the + SimpleJdbcInsert, in addition to specifying the + table name, you specify the name of the generated key column with the usingGeneratedKeyColumns method. - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; @@ -1474,7 +1565,7 @@ jdbcTemplate.update( } public void add(Actor actor) { - Map parameters = new HashMap(2); + Map<String, Object> parameters = new HashMap<String, Object>(2); parameters.put("first_name", actor.getFirstName()); parameters.put("last_name", actor.getLastName()); Number newId = insertActor.executeAndReturnKey(parameters); @@ -1482,27 +1573,26 @@ jdbcTemplate.update( } // ... additional methods -}]]>Here we can see the main difference when executing the - insert is that we don't add the id to the Map and we call the +}The main difference when executing the insert by this second + approach is that you do not add the id to the Map and you call the executeReturningKey method. This returns a - java.lang.Number object that we can use to create an - instance of the numerical type that is used in our domain class. It's - important to note that we can't rely on all databases to return a - specific Java class here, java.lang.Number is the - base class that we can rely on. If you have multiple auto-generated - columns or the generated values are non-numeric then you can use a - KeyHolder that is returned from the - executeReturningKeyHolder method. + java.lang.Number object with which you can create an + instance of the numerical type that is used in our domain class.You + cannot rely on all databases to return a specific Java class here; + java.lang.Number is the base class that you can rely + on. If you have multiple auto-generated columns, or the generated values + are non-numeric, then you can use a KeyHolder that is + returned from the executeReturningKeyHolder + method.
- Specifying the columns to use for a SimpleJdbcInsert + Specifying columns for a SimpleJdbcInsert - It's possible to limit the columns used for the insert by - specifying a list of column names to be used. This is accomplished using - the usingColumns method. + You can limit the columns for an insert by specifying a list of + column names with the usingColumns method: - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; @@ -1516,7 +1606,7 @@ jdbcTemplate.update( } public void add(Actor actor) { - Map parameters = new HashMap(2); + Map<String, Object> parameters = new HashMap<String, Object>(2); parameters.put("first_name", actor.getFirstName()); parameters.put("last_name", actor.getLastName()); Number newId = insertActor.executeAndReturnKey(parameters); @@ -1524,23 +1614,24 @@ jdbcTemplate.update( } // ... additional methods -}]]>The execution of the insert is the same as if we had - relied on the metadata for determining what columns to use. +}The execution of the insert is the same as if you had relied + on the metadata to determine which columns to use.
Using SqlParameterSource to provide parameter values - Using a Map to provide parameter values works fine, but it's not - the most convenient class to use. Spring provides a couple of - implementations of the SqlParameterSource - interface that can be used instead. The first one we'll look at is - BeanPropertySqlParameterSource which is a very - convenient class as long as you have a JavaBean compliant class that - contains your values. It will use the corresponding getter method to - extract the parameter values. Here is an example: - - Using a Map to provide parameter values + works fine, but it's not the most convenient class to use. Spring + provides a couple of implementations of the + SqlParameterSource interface that can be used + instead.The + first one is BeanPropertySqlParameterSource, + which is a very convenient class if you have a JavaBean-compliant class + that contains your values. It will use the corresponding getter method + to extract the parameter values. Here is an example: + + public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; @@ -1559,12 +1650,12 @@ jdbcTemplate.update( } // ... additional methods -}]]>Another option is the +}Another option is the MapSqlParameterSource that resembles a Map but provides a more convenient addValue method that can be chained. - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; @@ -1585,31 +1676,27 @@ jdbcTemplate.update( } // ... additional methods -}]]>As you can see, the configuration is the same, it;s just - the executing code that has to change to use these alternative input +}As you can see, the configuration is the same; only the + executing code has to change to use these alternative input classes.
- Calling a stored procedure using SimpleJdbcCall - - Let's now turn our attention to calling stored procedures using - the SimpleJdbcCall class. This class is designed - to make it as simple as possible to call a stored procedure. It takes - advantage of metadata present in the database to look up names of in and - out parameters. This means that you don't have to explicitly declare - parameters. You can of course still declare them if you prefer to do - that or if you have parameters that don't have an automatic mapping to a - Java class like ARRAY or STRUCT parameters. In our first example we will - look at a plain vanilla procedure that only returns scalar values in - form of VARCHAR and DATE. I have added a birthDate property to the Actor - class to get some variety in terms of return values. The example - procedure reads a specified actor entry and returns first_name, - last_name, and birth_date columns in the form of out parameters. Here is - the source for the procedure as it would look when using MySQL as the - database: - - Calling a stored procedure with SimpleJdbcCall + + The SimpleJdbcCall class leverages metadata + in the database to look up names of in and out + parameters, so that you do not have to declare them explicitly. You can + declare parameters if you prefer to do that, or if you have parameters + such as ARRAY or STRUCT that do not have an + automatic mapping to a Java class. The first example shows a simple + procedure that returns only scalar values in VARCHAR and + DATE format from a MySQL database. The example procedure + reads a specified actor entry and returns first_name, + last_name, and birth_date columns in the form + of out parameters. + + CREATE PROCEDURE read_actor ( IN in_id INTEGER, OUT out_first_name VARCHAR(100), OUT out_last_name VARCHAR(100), @@ -1618,17 +1705,22 @@ BEGIN SELECT first_name, last_name, birth_date INTO out_first_name, out_last_name, out_birth_date FROM t_actor where id = in_id; -END;]]>As you can see there are four parameters. One is an in - parameter "in_id" containing the id of the Actor we are looking up. The - remaining parameters are out parameters and they will be used to return - the data read from the table. +END;The in_id parameter contains the + id of the actor you are looking up. The out + parameters return the data read from the table. The SimpleJdbcCall is declared in a similar - manner to the SimpleJdbcInsert, no need to - subclass and we declare it in the initialization method. For this - example, all we need to specify is the name of the procedure. - - SimpleJdbcInsert. You should + instantiate and configure the class in the initialization method of your + data access layer. Compared to the StoredProcdedure class, you don't + have to create a subclass and you don't have to declare parameters that + can be looked up in the database metadata. Following + is an example of a SimpleJdbcCall configuration using the above stored + procedure. The only configuration option, in addition to the + DataSource, is the name of the stored + procedure. + + public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall procReadActor; @@ -1652,38 +1744,44 @@ END;]]>As you can see there are four parameters. One is an in } // ... additional methods -}]]>The execution of the call involves creating an - SqlParameterSource containing the in parameter. - It's important to match the name of the parameter declared in the stored - procedure. The case doesn't have to match since we use metadata to - determine how database objects should be referred to - what you specify - in your source for the stored procedure is not necessarily the way it is - stored in the database, some databases transform names to all upper case - while others use lower case or the case as specified. - - The execute method takes the in parameters - and returns a Map containing any out parameters keyed by the name as - specified in the stored procedure. In this case they are +}The code you write for the execution of the call involves + creating an SqlParameterSource containing the IN + parameter. It's + important to match the name provided for the input value with that of + the parameter name declared + in the stored procedure. The case does not have to match because you use + metadata to determine how database objects should be referred to in a + stored procedure. What is specified in the source for the stored + procedure is not necessarily the way it is stored in the database. Some + databases transform names to all upper case while others use lower case + or use the case as specified. + + The execute method takes the IN parameters + and returns a Map containing any out parameters keyed by + the name as specified in the stored procedure. In this case they are out_first_name, out_last_name and out_birth_date. - The last part of the execute method just - creates an Actor instance to use to return the data retrieved. Again, - it's important to match the names of the out parameters here. Also, the - case used for the names of the out parameters stored in the results map - are as they were defined in the database. You will either have to do a - case-insensitive lookup or instruct Spring to use a - CaseInsensitiveMap from the Jakarta Commons - project. The way you do that is by creating your own - JdbcTemplate and setting the + The last part of the execute method creates + an Actor instance to use to return the data retrieved. Again, it is + important to use the names of the out parameters as they + are declared in the stored procedure. Also, + the case in the names of the out parameters stored in the + results map matches that of the out parameter names in the + database, which could vary between databases. To + make your code more portable you should do a case-insensitive lookup or + instruct Spring to use a CaseInsensitiveMap from + the Jakarta Commons project. To do the latter, you create your own + JdbcTemplate and set the setResultsMapCaseInsensitive property to true. Then you pass this customized JdbcTemplate instance into the constructor of - your SimpleJdbcCall. You also have to include the - commons-collections.jar on your classpath for + your SimpleJdbcCall. You must include the + commons-collections.jar in your classpath for this to work. Here is an example of this configuration: - public class JdbcActorDao implements ActorDao { private SimpleJdbcCall procReadActor; public void setDataSource(DataSource dataSource) { @@ -1696,35 +1794,46 @@ END;]]>As you can see there are four parameters. One is an in // ... additional methods -}]]>By doing this, you don't have to worry about the case - used for the names of your returned out parameters. +}By taking this action, you avoid conflicts in the case used + for the names of your returned out parameters.
- Declaring parameters to use for a SimpleJdbcCall - - We have seen how the parameters are deduced based on metadata, but - you can declare then explicitly if you wish. This is done when the - SimpleJdbcCall is created and configured using - the declareParameters method that takes a - variable number of SqlParameter objects as input. - See the next section for details on how to define an - SqlParameter. - - We can opt to declare one, some or all of the parameters - explicitly. The parameter metadata is still being used. By calling the - method withoutProcedureColumnMetaDataAccess we - can specify that we would like to bypass any processing of the metadata - lookups for potential parameters and only use the declared ones. Another - situation that can arise is that one or more in parameters have default - values and we would like to leave them out of the call. To do that we - will just call the useInParameterNames to specify - the list of in parameter names to include. - - This is what a fully declared procedure call declaration of our - earlier example would look like: - - Explicitly declaring parameters to use for a + SimpleJdbcCall + + You have seen how the parameters are deduced based on metadata, + but you can declare then explicitly if you wish. You do this by creating + and configuring SimpleJdbcCall with the + declareParameters method, which takes a variable + number of SqlParameter objects 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 database. Currently Spring supports metadata + lookup of stored procedure calls for the 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, and Oracle. + + + You can opt to declare one, some, or all the parameters + explicitly. The parameter metadata is still used where you do not + declare parameters explicitly. To + bypass all processing of metadata lookups for potential parameters and + only use the declared parameters, you call the method + withoutProcedureColumnMetaDataAccess as part of + the declaration. Suppose that you have two or more different call + signatures declared for a database function. In this case you call the + useInParameterNames to specify the list of IN + parameter names to include for a given signature. + + The following example shows a fully declared procedure call, using + the information from the preceding example. + + public class JdbcActorDao implements ActorDao { private SimpleJdbcCall procReadActor; public void setDataSource(DataSource dataSource) { @@ -1745,79 +1854,77 @@ END;]]>As you can see there are four parameters. One is an in // ... additional methods -}]]>The execution and end results are the same, we are just - specifying all the details explicitly rather than relying on metadata. - This will be necessary if the database we use is not part of the - supported databases. Currently we support metadata lookup of stored - procedure calls for the 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 and Oracle. +}The execution and end results of the two examples are the + same; this one specifies all details explicitly rather than relying on + metadata.
How to define SqlParameters - To define a parameter to be used for the SimpleJdbc classes, and - also for the RDBMS operations classes covered in the following section, - you use an SqlParameter or one of its subclasses. - You typically specify the parameter name and SQL type in the - constructor. The SQL type is specified using the + To define a parameter for the SimpleJdbc classes and also for the + RDBMS operations classes, covered in , + you + use an SqlParameter or one of its subclasses. You + typically specify the parameter name and SQL type in the constructor. + The SQL type is specified using the java.sql.Types constants. We have already seen declarations like: - + new SqlParameter("in_id", Types.NUMERIC), + new SqlOutParameter("out_first_name", Types.VARCHAR), The first line with the SqlParameter - declares an in parameter. In parameters can be used for both stored + declares an IN parameter. IN parameters can be used for both stored procedure calls and for queries using the SqlQuery and its subclasses covered in the following section. The second line with the SqlOutParameter - declares an out parameter to be used in a stored procedure call. There - is also an SqlInOutParameter for inout - parameters, parameters that provide an in value to the procedure and - that also return a value + declares an out parameter to be used in a stored procedure + call. There is also an SqlInOutParameter for + InOut parameters, parameters that provide an + IN value to the procedure and that also return a + value. Only parameters declared as SqlParameter and SqlInOutParameter will be used to provide input values. This is different from the - StoredProcedure class which for backwards + StoredProcedure class, which for backwards compatibility reasons allows input values to be provided for parameters declared as SqlOutParameter. - In addition to the name and the SQL type you can specify - additional options. For in parameters you can specify a scale for - numeric data or a type name for custom database types. For out - parameters you can provide a RowMapper to handle - mapping of rows returned from a REF cursor. Another option is to specify - an SqlReturnType that provides and opportunity to + For IN parameters, in addition to the name and the SQL type, you + can specify a scale for numeric data or a type name for custom database + types. For out parameters, you can provide a + RowMapper to handle mapping of rows returned from + a REF cursor. Another option is to specify an + SqlReturnType that provides an opportunity to define customized handling of the return values.
Calling a stored function using SimpleJdbcCall - Calling a stored function is done almost exactly the same way as - calling a stored procedure. The only difference is that you need to - provide a function name rather than a procedure name. This is done by - using the withFunctionName method. Using this - method indicates that your call is to a function and the corresponding - call string for a function call will be generated. There is also a - specialized execute call executeFunction that - will return the function return value as an object of a specified type. - This way you don't have to retrieve the return value from the results - map. A similar convenience method named - executeObject is also available for stored - procedures that only have one out parameter. The following example is - based on a stored function named get_actor_name - that returns an actor's full name. Here is the MySQL source for this - function: - - You call a stored function in almost the same way as you call a + stored procedure, except that you provide a function name rather than a + procedure name. You use the withFunctionName + method as part of the configuration to indicate that we want to make a + call to a function, and the corresponding string for a function call is + generated. A specialized execute call, + executeFunction, is used to execute the function + and it returns the function return value as an object of a specified + type, which means you do not have to retrieve the return value from the + results map. A + similar convenience method named executeObject is + also available for stored procedures that only have one out + parameter. The following example is based on a stored function named + get_actor_name that returns an actor's full name. + Here is the MySQL source for this function: + + CREATE FUNCTION get_actor_name (in_id INTEGER) RETURNS VARCHAR(200) READS SQL DATA BEGIN DECLARE out_name VARCHAR(200); @@ -1825,13 +1932,13 @@ BEGIN INTO out_name FROM t_actor where id = in_id; RETURN out_name; -END;]]> +END; To call this function we again create a SimpleJdbcCall in the initialization method. - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall funcGetActorName; @@ -1852,44 +1959,44 @@ END;]]> } // ... additional methods -}]]>The execute method used returns a - String containing the return value from the - function call. +}The execute method used + returns a String containing the return value from + the function call.
Returning ResultSet/REF Cursor from a SimpleJdbcCall Calling a stored procedure or function that returns a result set - has always been a bit tricky. Some databases return result sets during - the JDBC results processing while others require an explicitly - registered out parameter of a specific type. Both approaches still needs - some additional processing to loop over the result set and process the + is a bit tricky. Some databases return result sets during the JDBC + results processing while others require an explicitly registered + out parameter of a specific type. Both approaches need + additional processing to loop over the result set and process the returned rows. With the SimpleJdbcCall you use the returningResultSet method and declare a RowMapper implementation to be used for a specific parameter. In the case where the result set is returned during the results processing, there are no names defined, so the returned - results will have to match the order you declare the - RowMapper implementations. The name specified - will still be used to store the processed list of results in the results - map returned from the execute statement. + results will have to match the order in which you declare the + RowMapper implementations. The name specified is + still used to store the processed list of results in the results map + that is returned from the execute statement. - For this example we will use a stored procedure that takes no in + The next example uses a stored procedure that takes no IN parameters and returns all rows from the t_actor table. Here is the MySQL source for this procedure: - CREATE PROCEDURE read_all_actors() BEGIN SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a; -END;]]>In order to call this procedure we need to declare the - RowMapper to be used. Since the class we want to - map to follows the JavaBean rules, we can use a +END;To call this procedure you declare the + RowMapper. Because the class you want to map to + follows the JavaBean rules, you can use a ParameterizedBeanPropertyRowMapper that is created by passing in the required class to map to in the newInstance method. - public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall procReadAllActors; @@ -1905,13 +2012,13 @@ END;]]>In order to call this procedure we need to declare the } public List getActorsList() { - Map m = procReadAllActors.execute(new HashMap(0)); + Map m = procReadAllActors.execute(new HashMap<String, Object>(0)); return (List) m.get("actors"); } // ... additional methods -}]]>The execute call passes in an empty Map since this call - doesn't take any parameters. The list of Actors is then retrieved from +}The execute call passes in an empty Map because this call + does not take any parameters. The list of Actors is then retrieved from the results map and returned to the caller.
@@ -1920,28 +2027,25 @@ END;]]>In order to call this procedure we need to declare the Modeling JDBC operations as Java objects The org.springframework.jdbc.object package - contains classes that allow one to access the database in a more - object-oriented manner. By way of an example, one can execute queries and - get the results back as a list containing business objects with the - relational column data mapped to the properties of the business object. - One can also execute stored procedures and run update, delete and insert + contains classes that allow you to access the database in a more + object-oriented manner. As an example, you can execute queries and get the + results back as a list containing business objects with the relational + column data mapped to the properties of the business object. You can also + execute stored procedures and run update, delete, and insert statements. - There is a view borne from experience acquired in the field - amongst some of the Spring developers that the various RDBMS operation + Many Spring developers believe that the various RDBMS operation classes described below (with the exception of the StoredProcedure class) can often be replaced with straight - JdbcTemplate calls... often it is simpler to use - and plain easier to read a DAO method that simply calls a method on a - JdbcTemplate direct (as opposed to encapsulating - a query as a full-blown class). - - It must be stressed however that this is just a - view... if you feel that you are getting measurable - value from using the RDBMS operation classes, feel free to continue - using these classes. + JdbcTemplate calls. Often it is simpler to write + a DAO method that simply calls a method on a + JdbcTemplate directly (as opposed to + encapsulating a query as a full-blown class). + + However, if you are getting measurable value from using the RDBMS + operation classes, continue using these classes.
@@ -1954,7 +2058,7 @@ END;]]>In order to call this procedure we need to declare the object per row obtained from iterating over the ResultSet that is created during the execution of the query. The SqlQuery class is - rarely used directly since the MappingSqlQuery + rarely used directly because the MappingSqlQuery subclass provides a much more convenient implementation for mapping rows to Java classes. Other implementations that extend SqlQuery are @@ -1969,11 +2073,11 @@ END;]]>In order to call this procedure we need to declare the which concrete subclasses must implement the abstract mapRow(..) method to convert each row of the supplied ResultSet into an object of the - type specified. Below is a brief example of a custom query that maps the - data from the t_actor relation to an instance of the + type specified. The following example shows a custom query that maps the + data from the t_actor relation to an instance of the Actor class. - { + public class ActorMappingQuery extends MappingSqlQuery<Actor> { public ActorMappingQuery(DataSource ds) { super(ds, "select id, first_name, last_name from t_actor where id = ?"); @@ -1990,29 +2094,30 @@ END;]]>In order to call this procedure we need to declare the return actor; } -}]]> +} The class extends MappingSqlQuery - parameterized with the Actor type. We provide a - constructor for this customer query that takes the + parameterized with the Actor type. The + constructor for this customer query takes the DataSource as the only parameter. In this - constructor we call the constructor on the superclass with the + constructor you call the constructor on the superclass with the DataSource and the SQL that should be executed to retrieve the rows for this query. This SQL will be used to create a PreparedStatement so it may contain place holders for any parameters to be passed in during - execution. Each parameter must be declared using the + execution.You + must declare each parameter using the declareParameter method passing in an - SqlParameter. The + SqlParameter. The SqlParameter takes a name and the JDBC type as - defined in java.sql.Types. After all parameters - have been defined we call the compile() method so the - statement can be prepared and later be executed. This class is thread - safe once it has been compiled, so as long as these classes are created - when the DAO is initialized they can be kept as instance variable and be - reused. + defined in java.sql.Types. After you define all + parameters, you call the compile() method so the + statement can be prepared and later executed. This class is thread-safe + after it is compiled, so as long as these instances + are created when the DAO is initialized they can be kept as instance + variables and be reused. - private ActorMappingQuery actorMappingQuery; @Autowired public void setDataSource(DataSource dataSource) { @@ -2021,19 +2126,20 @@ public void setDataSource(DataSource dataSource) { public Customer getCustomer(Long id) { return actorMappingQuery.findObject(id); -}]]> +} The method in this example retrieves the customer with the id that is passed in as the only parameter. Since we only want one object - returned we simply call the convenience method findObject with the id as - parameter. If we instead had a query the returned a list of objects and - took additional parameters then we would use one of the execute methods - that takes an array of parameter values passed in as varargs. - - searchForActors(int age, String namePattern) { - List actors = actorSearchMappingQuery.execute(age, namePattern); + returned we simply call the convenience method findObject + with the id as parameter. If we instead had a query the returned a list + of objects and took additional parameters then we would use one of the + execute methods that takes an array of parameter values passed in as + varargs. + + public List<Actor> searchForActors(int age, String namePattern) { + List<Actor> actors = actorSearchMappingQuery.execute(age, namePattern); return actors; -}]]> +}
@@ -2044,13 +2150,16 @@ public Customer getCustomer(Long id) { RdbmsOperation classes, an update can have parameters and is defined in SQL. This class provides a number of update(..) methods analogous to the - execute(..) methods of query objects. This - class is concrete. Although it can be subclassed (for example to add a - custom update method - like in this example where we call it execute) it - can easily be parameterized by setting SQL and declaring - parameters. + execute(..) methods of query objects. The + SQLUpdate class is concrete. It can be + subclassed, for example, to add a custom update method, as in the + following snippet where it's simply called + execute. However, + you don't have to subclass the SqlUpdate class + since it can easily be parameterized by setting SQL and declaring + parameters. - import java.sql.Types; import javax.sql.DataSource; @@ -2075,7 +2184,7 @@ public class UpdateCreditRating extends SqlUpdate { public int execute(int id, int rating) { return update(rating, id); } -}]]> +}
@@ -2091,60 +2200,55 @@ public class UpdateCreditRating extends SqlUpdate { The inherited sql property will be the name of the stored procedure in the RDBMS. - To define a parameter to be used for the StoredProcedure class, - you use an SqlParameter or one of its subclasses. - You must specify the parameter name and SQL type in the constructor. The - SQL type is specified using the java.sql.Types - constants. We have already seen declarations like: + To define a parameter for the + StoredProcedure class, you use an + SqlParameter or one of its subclasses. You must + specify the parameter name and SQL type in the constructor like in the + following code snippet. The SQL type is specified using the + java.sql.Types constants. - + new SqlParameter("in_id", Types.NUMERIC), + new SqlOutParameter("out_first_name", Types.VARCHAR), The first line with the SqlParameter - declares an in parameter. In parameters can be used for both stored + declares an IN parameter. IN parameters can be used for both stored procedure calls and for queries using the SqlQuery and its subclasses covered in the following section. The second line with the SqlOutParameter - declares an out parameter to be used in the stored procedure call. There - is also an SqlInOutParameter for inout - parameters, parameters that provide an in value to the procedure and - that also return a value - - - Parameters declared as SqlParameter and - SqlInOutParameter will always be used to - provide input values. In addition to this any parameter declared as - SqlOutParameter where an non-null input value - is provided will also be used as an input parameter. - - - In addition to the name and the SQL type you can specify - additional options. For in parameters you can specify a scale for - numeric data or a type name for custom database types. For out - parameters you can provide a RowMapper to handle - mapping of rows returned from a REF cursor. Another option is to specify - an SqlReturnType that provides and opportunity to - define customized handling of the return values. + declares an out parameter to be used in the stored + procedure call. There is also an + SqlInOutParameter for + InOut parameters, parameters that provide an + in value to the procedure and that also return a + value. + + For in parameters, in addition to the + name and the SQL type, you can specify a scale for numeric data or a + type name for custom database types. For out parameters you + can provide a RowMapper to handle mapping of rows + returned from a REF cursor. Another option is to specify an + SqlReturnType that enables you to define + customized handling of the return values. Here is an example of a simple DAO that uses a StoredProcedure to call a function, - sysdate(), that comes with any Oracle database. To + sysdate(),which comes with any Oracle database. To use the stored procedure functionality you have to create a class that - extends StoredProcedure. In this example the + extends StoredProcedure. In this example, the StoredProcedure class is an inner class, but if - you need to reuse the StoredProcedure you would - declare it as a top-level class. There are no input parameters in this - example, but there is an output parameter that is declared as a date - type using the class SqlOutParameter. The - execute() method executes the procedure and extracts - the returned date from the results Map. The - results Map has an entry for each declared output + you need to reuse the StoredProcedure you declare + it as a top-level class. This example has no input parameters, but an + output parameter is declared as a date type using the class + SqlOutParameter. The execute() + method executes the procedure and extracts the returned date from the + results Map. The results + Map has an entry for each declared output parameter, in this case only one, using the parameter name as the key. - import java.sql.Types; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -2182,18 +2286,18 @@ public class StoredProcedureDao { public Date execute() { // the 'sysdate' sproc has no input parameters, so an empty Map is supplied... - Map results = execute(new HashMap()); + Map<String, Object> results = execute(new HashMap<String, Object>()); Date sysdate = (Date) results.get("date"); return sysdate; } } -}]]> +} - Below is an example of a StoredProcedure - that has two output parameters (in this case Oracle REF cursors). + The following example of a StoredProcedure + has two output parameters (in this case, Oracle REF cursors). - import oracle.jdbc.OracleTypes; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.object.StoredProcedure; @@ -2212,34 +2316,34 @@ public class TitlesAndGenresStoredProcedure extends StoredProcedure { compile(); } - public Map execute() { + public Map<String, Object> execute() { // again, this sproc has no input parameters, so an empty Map is supplied - return super.execute(new HashMap()); + return super.execute(new HashMap<String, Object>()); } -}]]> +} Notice how the overloaded variants of the declareParameter(..) method that have been used in the TitlesAndGenresStoredProcedure constructor are passed RowMapper implementation instances; this is a very convenient and powerful way to reuse existing - functionality. (The code for the two + functionality. The code for the two RowMapper implementations is provided - below in the interest of completeness.) + below. - First the TitleMapper class, which simply - maps a ResultSet to a + The TitleMapper class maps a + ResultSet to a Title domain object for each row in the supplied - ResultSet. + ResultSet: - import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import com.foo.domain.Title; -public final class TitleMapper implements RowMapper { +public final class TitleMapper implements RowMapper<Title> { public Title mapRow(ResultSet rs, int rowNum) throws SQLException { Title title = new Title(); @@ -2247,35 +2351,35 @@ public final class TitleMapper implements RowMapper<Title> { title.setName(rs.getString("name")); return title; } -}]]></programlisting> +}</programlisting> - <para>Second, the <classname>GenreMapper</classname> class, which again - simply maps a <interfacename>ResultSet</interfacename> to a + <para>The <classname>GenreMapper</classname> class maps a + <interfacename>ResultSet</interfacename> to a <classname>Genre</classname> domain object for each row in the supplied <interfacename>ResultSet</interfacename>.</para> - <programlisting language="java"><![CDATA[import org.springframework.jdbc.core.RowMapper; + <programlisting language="java">import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import com.foo.domain.Genre; -public final class GenreMapper implements RowMapper<Genre> { +public final class GenreMapper implements RowMapper<Genre> { public Genre mapRow(ResultSet rs, int rowNum) throws SQLException { return new Genre(rs.getString("name")); } -}]]></programlisting> +}</programlisting> - <para>If you need to pass parameters to a stored procedure (that is the - stored procedure has been declared as having one or more input - parameters in its definition in the RDBMS), you should code a strongly - typed <literal>execute(..)</literal> method which would delegate to the - superclass' (untyped) <literal>execute(Map parameters)</literal> (which - has <literal>protected</literal> access); for example:</para> + <para>To pass parameters to a stored procedure that has one or more + input parameters in its definition in the RDBMS, you can code a strongly + typed <literal>execute(..)</literal> method that would delegate to the + superclass' untyped <literal>execute(Map parameters)</literal> method + (which has <literal>protected</literal> access); <!--Wording of preceding line is very awkward and doesn't track well at all. Please revise. Don't overuse parentheses. TR: Revised.-->for + example:</para> - <programlisting language="java"><![CDATA[import oracle.jdbc.OracleTypes; + <programlisting language="java">import oracle.jdbc.OracleTypes; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.core.SqlParameter; import org.springframework.jdbc.object.StoredProcedure; @@ -2299,55 +2403,56 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure { compile(); } - public Map<String, Object> execute(Date cutoffDate) { - Map<String, Object> inputs = new HashMap<String, Object>(); + public Map<String, Object> execute(Date cutoffDate) { + Map<String, Object> inputs = new HashMap<String, Object>(); inputs.put(CUTOFF_DATE_PARAM, cutoffDate); return super.execute(inputs); } -}]]></programlisting> +}</programlisting> </section> </section> <section id="jdbc-parameter-handling"> - <title>Common issues with parameter and data value handling + Common problems with parameter and data value handling - There are some issues involving parameters and data values that are - common across all the different approaches provided by the Spring JDBC - Framework. + Common problems with parameters and data values exist in the + different approaches provided by the Spring Framework JDBC.
Providing SQL type information for parameters - Most of the time Spring will assume the SQL type of the parameters - based on the type of parameter passed in. It is possible to explicitly - provide the SQL type to be used when setting parameter values. This is - sometimes necessary to correctly set NULL values. + Usually Spring determines the SQL type of the parameters based on + the type of parameter passed in. It is possible to explicitly provide + the SQL type to be used when setting parameter values. This is sometimes + necessary to correctly set NULL values. - There are a few different ways this can be accomplished: + You can provide SQL type information in several ways: - Many of the update and query methods of the + Many update and query methods of the JdbcTemplate take an additional parameter in - the form of an int array. This array should contain the SQL type - using constant values from the java.sql.Types - class. There must be one entry for each parameter. + the form of an int array. This array is used to + indicate the SQL type of the coresponding parameter using constant + values from the java.sql.Types class. Provide + one entry for each parameter. - You can wrap the parameter value that needs this additional - information using the SqlParameterValue - class. Create a new instance for each value and pass in the SQL type - and parameter value in the constructor. You can also provide an - optional scale parameter for numeric values. + You can use the SqlParameterValue class + to wrap the parameter value that needs this additional information. + Create + a new instance for each value and pass in the SQL type and parameter + value in the constructor. You can also provide an optional scale + parameter for numeric values. - For methods working with named parameters, you can use the + For methods working with named parameters, use the SqlParameterSource classes BeanPropertySqlParameterSource or MapSqlParameterSource. They both have methods @@ -2360,20 +2465,20 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure {
Handling BLOB and CLOB objects - You can store images and other binary objects as well and large - chunks of text. These large object are called BLOB for binary data and - CLOB for character data. Spring lets you handle these large objects - using the JdbcTemplate directly and also when using the higher - abstractions provided by RDBMS Objects and the SimpleJdbc classes. All + You can store images, other binary objects, and large chunks of + text. These large object are called BLOB for binary data and CLOB for + character data. In Spring you can handle these large objects by using + the JdbcTemplate directly and also when using the higher abstractions + provided by RDBMS Objects and the SimpleJdbc classes. All of these approaches use an implementation of the LobHandler interface for the actual management of the LOB data. The LobHandler provides access to a - LobCreator, via the - getLobCreator method, for creating new LOB - objects to be inserted. + LobCreatorclass, + through the getLobCreator method, used for + creating new LOB objects to be inserted. The LobCreator/LobHandler provides the - following support for LOB in- and output: + following support for LOB input and output: @@ -2412,19 +2517,20 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure { - We will now show an example of how to create and insert a BLOB. We - will later see how to read it back from the database. + The next example shows how to create and insert a BLOB. Later you + will see how to read it back from the database. - This example uses a JdbcTemplate and an implementation of the - AbstractLobCreatingPreparedStatementCallback. There is one method that - must be implemented and it is "setValues". In this method you will be - provided with a LobCreator that can be used to set the values for the - LOB columns in your SQL insert statement. + This example uses a JdbcTemplate and an + implementation of the + AbstractLobCreatingPreparedStatementCallback. + It implements one method, setValues. This method provides a + LobCreator that you use to set the values for the LOB + columns in your SQL insert statement. - We are assuming that we have a variable named 'lobHandler' that - already is set to an instance of a - DefaultLobHandler. This is typically done using - dependency injection. + For this example we assume that there is a variable, + lobHandler, that already is set to an instance + of a DefaultLobHandler. You typically set this + value through dependency injection. @@ -2435,7 +2541,7 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure { - final File blobIn = new File("spring2004.jpg"); final InputStream blobIs = new FileInputStream(blobIn); final File clobIn = new File("large.txt"); final InputStream clobIs = new FileInputStream(clobIn); @@ -2452,30 +2558,32 @@ jdbcTemplate.execute( } ); blobIs.close(); -clobReader.close();]]> +clobReader.close(); - Here we use the lobHandler that in this example is a plain - DefaultLobHandler + Pass in the lobHandler that in this example is a plain + DefaultLobHandler - Using the method setClobAsCharacterStream - we pass in the contents of the CLOB + Using the method + setClobAsCharacterStream, pass in the + contents of the CLOB. Using the method - setBlobAsBinartStream we pass in the - contents of the BLOB + setBlobAsBinartStream, pass in the contents + of the BLOB. - Now it's time to read the LOB data from the database. Again, we - use a JdbcTempate and we have the same instance variable 'lobHandler' - with a reference to a DefaultLobHandler. + Now it's time to read the LOB data from the database. Again, you + use a JdbcTempate with the same instance variable + lobHandler and a reference to a + DefaultLobHandler. @@ -2484,10 +2592,10 @@ clobReader.close();]]> - > l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table", - new RowMapper>() { - public Map mapRow(ResultSet rs, int i) throws SQLException { - Map results = new HashMap(); + List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table", + new RowMapper<Map<String, Object>>() { + public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException { + Map<String, Object> results = new HashMap<String, Object>(); String clobText = lobHandler.getClobAsString(rs, "a_clob"); results.put("CLOB", clobText); byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob"); @@ -2495,17 +2603,17 @@ clobReader.close();]]> return results; } }); -]]> + - Using the method getClobAsString we - retrieve the contents of the CLOB + Using the method getClobAsString, + retrieve the contents of the CLOB. - Using the method getBlobAsBytes we - retrieve the contents of the BLOB + Using the method getBlobAsBytes, + retrieve the contents of the BLOB. @@ -2516,54 +2624,53 @@ clobReader.close();]]> The SQL standard allows for selecting rows based on an expression that includes a variable list of values. A typical example would be - "select * from T_ACTOR where id in (1, 2, 3)". This variable list is not - directly supported for prepared statements by the JDBC standard - there - is no way of declaring a variable number of place holders. You would - have to either have a number of variations with the desired number of - place holders prepared or you would have to dynamically generate the SQL - string once you know how many place holders are required. The named - parameter support provided in the - NamedParameterJdbcTemplate and + "select * from T_ACTOR where id in (1, 2, 3). This variable + list is not directly supported for prepared statements by the JDBC + standard; you cannot declare a variable number of placeholders. You need + a number of variations with the desired number of placeholders prepared, + or you need to generate the SQL string dynamically once you know how + many placeholders are required. The named parameter support provided in + the NamedParameterJdbcTemplate and SimpleJdbcTemplate takes the latter approach. - When you pass in the values you should pass them in as a - java.util.List of primitive objects. This list - will be used to insert the required place holders and pass in the values - during the statement execution. + Pass in the values as a java.util.List of + primitive objects. This list will be used to insert the required + placeholders and pass in the values during the statement + execution. - You need to be careful when passing in a large number of values. - The JDBC standard doesn't guarantee that you can use more than 100 - values for an IN expression list. Various databases exceed this - number, but they usually have a hard limit for how many values are - allowed. Oracle's limit for instance is 1000. + Be careful when passing in many values. The JDBC standard does + not guarantee that you can use more than 100 values for an + in expression list. Various databases exceed this number, + but they usually have a hard limit for how many values are allowed. + Oracle's limit is 1000. In addition to the primitive values in the value list, you can create a java.util.List of object arrays. This - would support a case where there are multiple expressions defined for - the IN clause like "select * from T_ACTOR where (id, last_name) in ((1, - 'Johnson'), (2, 'Harrop'))". This of course requires that your database - supports this syntax. + list would support multiple expressions defined for the in + clause such as "select * from T_ACTOR where (id, last_name) in + ((1, 'Johnson'), (2, 'Harrop'))". This + of course requires that your database supports this syntax.
Handling complex types for stored procedure calls - When calling stored procedures it's sometimes possible to use - complex types specific to the database. To accommodate these types - Spring provides a SqlReturnType for handling them - when they are returned from the stored procedure call and + When you call stored procedures you can sometimes use complex + types specific to the database. To accommodate these types, Spring + provides a SqlReturnType for handling them when + they are returned from the stored procedure call and SqlTypeValue when they are passed in as a parameter to the stored procedure. - Here is an example of returning the value of an Oracle STRUCT - object of the user declared type "ITEM_TYPE". The - SqlReturnType interface has a single method named - "getTypeValue" that must be implemented. This - interface is used as part of the declaration of an - SqlOutParameter. + Here is an example of returning the value of an Oracle + STRUCT object of the user declared type + ITEM_TYPE. The SqlReturnType + interface has a single method named getTypeValue + that must be implemented. This interface is used as part of the + declaration of an SqlOutParameter. - final TestItem - new TestItem(123L, "A test item", new SimpleDateFormat("yyyy-M-d").parse("2010-12-31");); declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE", @@ -2578,16 +2685,17 @@ declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE", item.setExpirationDate((java.util.Date)attr[2]); return item; } - }));]]>Going from Java to the database and passing in the - value of a TestItem into a stored procedure is - done using the SqlTypeValue. The + }));You use the SqlTypeValue to + pass in the value of a Java object like TestItem + into a stored procedure. The SqlTypeValue interface has a single method named - "createTypeValue" that must be implemented. The - active connection is passed in and can be used to create database - specific objects like StructDescriptors or - ArrayDescriptors + createTypeValue that you must implement. The + active connection is passed in, and you can use it to create + database-specific objects such as + StructDescriptors, as shown in the following + example, or ArrayDescriptors. - final TestItem - new TestItem(123L, "A test item", new SimpleDateFormat("yyyy-M-d").parse("2010-12-31");); SqlTypeValue value = new AbstractSqlTypeValue() { @@ -2601,18 +2709,18 @@ SqlTypeValue value = new AbstractSqlTypeValue() { }); return item; } -};]]>This SqlTypeValue can now be - added to the Map containing the input parameters for the execute call of - the stored procedure. +};This SqlTypeValue can now be added + to the Map containing the input parameters for the execute call of the + stored procedure. - Another use for the SqlTypeValue is for - passing in an array of values to an Oracle stored procedure. Oracle has - its own internal ARRAY class that must be used in - this case and we can use the SqlTypeValue to - create an instance of the Oracle ARRAY and - populate it with values from our Java array. + Another use for the SqlTypeValue is passing + in an array of values to an Oracle stored procedure. Oracle has its own + internal ARRAY class that must be used in this + case, and you can use the SqlTypeValue to create + an instance of the Oracle ARRAY and populate it + with values from the Java ARRAY. - final Long[] ids = new Long[] {1L, 2L}; SqlTypeValue value = new AbstractSqlTypeValue() { protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException { @@ -2620,7 +2728,7 @@ SqlTypeValue value = new AbstractSqlTypeValue() { ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids); return idArray; } -};]]> +};
@@ -2630,32 +2738,32 @@ SqlTypeValue value = new AbstractSqlTypeValue() { The org.springframework.jdbc.datasource.embedded package provides support for embedded Java database engines. Support for HSQL, H2, and Derby is provided natively. There is - also an extensible API for plugging in new embedded database types and + url="http://www.h2database.com">H2, and Derby is provided natively. You + can also use an extensible API to plug in new embedded database types and DataSource implementations.
Why use an embedded database? An embedded database is useful during the development phase of a - project due to its lightweight nature. Ease of configuration, quick - startup time, testability, and the ability to rapidly evolve SQL during - development are just some of the benefits of using an embedded - database. + project because of its lightweight nature. Benefits include ease of + configuration, quick startup time, testability, and the ability to + rapidly evolve SQL during development.
Creating an embedded database instance using Spring XML - When you wish to expose an embedded database instance as a bean in - a Spring ApplicationContext, use the embedded-database tag in the - spring-jdbc namespace: - - - -]]> + 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: <jdbc:embedded-database id="dataSource"> + <jdbc:script location="classpath:schema.sql"/> + <jdbc:script location="classpath:test-data.sql"/> + </jdbc:embedded-database> + - The configuration above creates an embedded HSQL database + 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 available to the Spring container as a bean of type javax.sql.DataSource. @@ -2664,24 +2772,24 @@ SqlTypeValue value = new AbstractSqlTypeValue() {
- Creating an embedded database instance programatically + Creating an embedded database instance programmatically The EmbeddedDatabaseBuilder class provides a fluent API for constructing an embedded database programmatically. Use this when you need to create an embedded database instance in a standalone environment, such as a data access object unit test: - EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); EmbeddedDatabase db = builder.type(H2).script("schema.sql").script("test-data.sql").build(); // do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource) db.shutdown() -]]> +
Extending the embedded database support - Spring Jdbc's 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 as Apache @@ -2699,38 +2807,50 @@ SqlTypeValue value = new AbstractSqlTypeValue() { community at jira.springframework.org.
+
- Using HSQL - - Support for HSQL 1.0.0 to 2.0.0 is provided. - HSQL is the default database embedded database that will be used if no type is specified explicitly. - To specify HSQL explicitly, set the type attribute of the embedded-database tag to HSQL. - If using the builder API, call the type(EmbeddedDatabaseType) method with EmbeddedDatabaseType.HSQL. - + Using HSQL + + Spring supports HSQL 1.0.0 to 2.0.0. HSQL is the default embedded + database if no type is 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 + type(EmbeddedDatabaseType) method with + EmbeddedDatabaseType.HSQL.
+
- Using H2 - - Support for H2 1.8.0 to 2.0.0 is provided. - To enable H2, set the type attribute of the embedded-database tag to H2. - If using the builder API, call the type(EmbeddedDatabaseType) method with EmbeddedDatabaseType.H2. - + Using H2 + + Spring supports H2 1.8.0 to 2.0.0. To enable H2, set the + type attribute of the + embedded-database tag to H2. If + you are using the builder API, call the + type(EmbeddedDatabaseType) method with + EmbeddedDatabaseType.H2.
+
- Using Derby - - Support for Apache Derby 10.5.1.1 to 10.6.0 is provided. - To enable Derby, set the type attribute of the embedded-database tag to Derby. - If using the builder API, call the type(EmbeddedDatabaseType) method with EmbeddedDatabaseType.Derby. - + Using Derby + + Spring supports Apache Derby 10.5.1.1 to 10.6.0. To enable Derby, + set the type attribute of the + embedded-database tag to Derby. If + using the builder API, call the + type(EmbeddedDatabaseType) method with + EmbeddedDatabaseType.Derby.
+
- Unit testing data access logic with an EmbeddedDatabase - - Embedded databases provide a lightweight way to test data access code. - A basic data access unit test template that uses an embedded database is provided below: - - 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: + + public class DataAccessUnitTestTemplate { private EmbeddedDatabase db; @@ -2739,19 +2859,19 @@ public class DataAccessUnitTestTemplate { // creates a HSQL in-memory db populated from classpath:schema.sql and classpath:test-data.sql db = EmbeddedDatabaseBuilder.buildDefault(); } - + @Test public void testDataAccess() { JdbcTemplate template = new JdbcTemplate(db); template.query(...); } - + @After public void tearDown() { db.shutdown(); } } -]]> +