3043 lines
146 KiB
XML
3043 lines
146 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||
<chapter id="jdbc">
|
||
<title>Data access with JDBC</title>
|
||
|
||
<section id="jdbc-introduction">
|
||
<title>Introduction to Spring Framework JDBC</title>
|
||
|
||
<para>The value-add provided by the Spring Framework JDBC abstraction is
|
||
perhaps best shown by the sequence of actions outlined in the table
|
||
below. The table shows what actions Spring will take care of and which
|
||
actions are the responsibility of you, the application developer.<!--Is this sequence correct, as far as what developer does and doesn't do? Does it adhere to info in the rest of the chapter?
|
||
--><!--How does JDBC know what connection parameters are if a human does not at some point define them?--><!--TR: OK. I have rewritten this as a table indicating who has what responsibility. --></para>
|
||
|
||
<table align="left" width="">
|
||
<title>Spring JDBC - who does what?</title>
|
||
|
||
<tgroup cols="3">
|
||
<colspec colnum="1" colwidth="350" />
|
||
|
||
<colspec colnum="2" colwidth="40" />
|
||
|
||
<colspec colnum="3" colwidth="40" />
|
||
|
||
<thead>
|
||
<row>
|
||
<entry align="center">Action</entry>
|
||
|
||
<entry align="center">Spring</entry>
|
||
|
||
<entry align="center">You</entry>
|
||
</row>
|
||
</thead>
|
||
|
||
<tbody>
|
||
<row>
|
||
<entry>Define connection parameters.</entry>
|
||
|
||
<entry align="center"><emphasis role="bold"></emphasis></entry>
|
||
|
||
<entry align="center">X</entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Open the connection.</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Specify the SQL statement.</entry>
|
||
|
||
<entry align="center"></entry>
|
||
|
||
<entry align="center">X</entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Declare parameters and provide parameter values</entry>
|
||
|
||
<entry align="center"></entry>
|
||
|
||
<entry align="center">X</entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Prepare and execute the statement.</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Set up the loop to iterate through the results (if
|
||
any).</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Do the work for each iteration.</entry>
|
||
|
||
<entry align="center"></entry>
|
||
|
||
<entry align="center">X</entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Process any exception.</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Handle transactions.</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
|
||
<row>
|
||
<entry>Close the connection, statement and resultset.</entry>
|
||
|
||
<entry align="center">X</entry>
|
||
|
||
<entry align="center"></entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
|
||
<para>The Spring Framework takes care of all the low-level details that
|
||
can make JDBC such a tedious API to develop with.</para>
|
||
|
||
<section id="jdbc-choose-style">
|
||
<title>Choosing an approach for JDBC database access</title>
|
||
|
||
<para>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.</para>
|
||
|
||
<note>
|
||
<para>Spring 3.0 updates all of the following approaches with Java 5
|
||
support such as generics and varargs.<!--Is there a formal name for varargs? Is this written correctly?I've inserted this note to avoid redundancy below.--></para>
|
||
</note>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para><emphasis role="bold">JdbcTemplate</emphasis> 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.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><emphasis role="bold">NamedParameterJdbcTemplate</emphasis>
|
||
wraps a <code>JdbcTemplate</code> 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.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><emphasis role="bold">SimpleJdbcTemplate</emphasis> combines
|
||
the most frequently used operations of JdbcTemplate and
|
||
NamedParameterJdbcTemplate.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><emphasis role="bold">SimpleJdbcInsert and
|
||
SimpleJdbcCall</emphasis> 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. <!--Revise preceding to clarify: You *must* use this approach w/ SimpleJdbcTemplate, it is *recommended*, or you *can*?
|
||
TR: OK. I removed the sentence since it isn;t entirely accurate. The implementation uses a plain JdbcTemplate internally.-->
|
||
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.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para><emphasis role="bold">RDBMS Objects including MappingSqlQuery,
|
||
SqlUpdate and StoredProcedure</emphasis> 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.</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section id="jdbc-packages">
|
||
<title>Package hierarchy<!--I have provided links to main sections that deal with most packages. TR: OK--></title>
|
||
|
||
<para>The Spring Framework's JDBC abstraction framework consists of four
|
||
different packages, namely <literal>core</literal>,
|
||
<literal>datasource</literal>, <literal>object</literal>, and
|
||
<literal>support</literal>.</para>
|
||
|
||
<para>The <literal>org.springframework.jdbc.core</literal> package
|
||
contains the <classname>JdbcTemplate</classname> class and its various
|
||
callback interfaces, plus a variety of related classes. A subpackage
|
||
named <literal>org.springframework.jdbc.core.simple</literal> contains
|
||
the <classname>SimpleJdbcTemplate</classname> class and the related
|
||
<classname>SimpleJdbcInsert</classname> and
|
||
<classname>SimpleJdbcCall</classname> classes. Another subpackage named
|
||
<literal>org.springframework.jdbc.core.namedparam</literal> contains the
|
||
<classname>NamedParameterJdbcTemplate</classname> class and the related
|
||
support classes. See <xref linkend="jdbc-core" />, <xref
|
||
linkend="jdbc-advanced-jdbc" />, and <xref
|
||
linkend="jdbc-simple-jdbc" /></para>
|
||
|
||
<para>The <literal>org.springframework.jdbc.datasource</literal> package
|
||
contains a utility class for easy
|
||
<interfacename>DataSource</interfacename> access, and various simple
|
||
<interfacename>DataSource</interfacename> implementations that can be
|
||
used for testing and running unmodified JDBC code outside of a Java EE
|
||
container. A subpackage named
|
||
<literal>org.springfamework.jdbc.datasource.embedded</literal> provides
|
||
support for creating in-memory database instances using Java database
|
||
engines such as HSQL and H2. See <xref linkend="jdbc-connections" /> and
|
||
<xref linkend="jdbc-embedded-database-support" /></para>
|
||
|
||
<para>The <literal>org.springframework.jdbc.object</literal> package
|
||
contains classes that represent RDBMS queries, updates, and stored
|
||
procedures as thread safe, reusable objects. See <xref
|
||
linkend="jdbc-object" />.This approach is modeled by JDO, although of
|
||
course objects returned by queries are <quote>disconnected</quote> from
|
||
the database. This higher level of JDBC abstraction depends on the
|
||
lower-level abstraction in the
|
||
<literal>org.springframework.jdbc.core</literal> package.</para>
|
||
|
||
<para><!--Need x-ref for preceding and next sentences. TR: Revised, please review. Combined to single paragraph about exception translation.-->The
|
||
<literal>org.springframework.jdbc.support</literal> package provides
|
||
<classname>SQLException</classname> translation functionality and some
|
||
utility classes. Exceptions thrown during JDBC processing are translated
|
||
to exceptions defined in the <literal>org.springframework.dao</literal>
|
||
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, 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 <xref
|
||
linkend="jdbc-SQLExceptionTranslator" />.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-core">
|
||
<title>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--></title>
|
||
|
||
<section id="jdbc-JdbcTemplate">
|
||
<title><classname>JdbcTemplate</classname></title>
|
||
|
||
<para>The <classname>JdbcTemplate</classname> class is the central class
|
||
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
|
||
<classname>JdbcTemplate</classname> class executes SQL queries, update
|
||
statements and stored procedure calls, performs iteration over
|
||
<interfacename>ResultSet</interfacename>s and extraction of returned
|
||
parameter values.<!--The wording of the preceding sentence does not track. Which is correct: the class *executes* queries, *updated* statements, --><!--and stored procedure calls...OR the class *executes* queries and *updates* statements and stored procedure calls. Second part of--><!--sentence; is this clear? It *imitates* iteration and extraction? TR: Revised, please review. The class executes *SQL queries*, *update statements* or *stored procedure calls* ...-->
|
||
It also catches JDBC exceptions and translates them to the generic, more
|
||
informative, exception hierarchy defined in the
|
||
<literal>org.springframework.dao</literal> package.</para>
|
||
|
||
<para>When you use the <classname>JdbcTemplate</classname> for your
|
||
code, you only need to implement callback interfaces, giving them a
|
||
clearly defined contract. The
|
||
<interfacename>PreparedStatementCreator</interfacename> callback
|
||
interface creates a prepared statement given a
|
||
<interfacename>Connection</interfacename> provided by this class,
|
||
providing SQL and any necessary parameters. The same is true for the
|
||
<interfacename>CallableStatementCreator</interfacename> interface, which
|
||
creates callable statements. The
|
||
<interfacename>RowCallbackHandler</interfacename> interface extracts
|
||
values from each row of a
|
||
<interfacename>ResultSet</interfacename>.</para>
|
||
|
||
<!--and stored procedure calls? TR: they are handled by the CallableStatement; Queries and update statements are handled by PreparedStatement.-->
|
||
|
||
<para>The <classname>JdbcTemplate</classname> can be used within a DAO
|
||
implementation through direct instantiation with a
|
||
<interfacename>DataSource</interfacename> reference, or be configured in
|
||
a Spring IoC container and given to DAOs as a bean reference. <note>
|
||
<para>The <interfacename>DataSource</interfacename> 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.<!--I've revised so that it reads better, but please clarify second sentence: Specify what *the first case* is, what--><!--do you mean by *is given* and it's given to *which* service? First mention of a service. Specify what *second--><!-- case* is and what you mean by *is given*. TR: OK.--></para>
|
||
</note></para>
|
||
|
||
<para>All SQL issued by this class is logged at the
|
||
<literal>DEBUG</literal> level under the category corresponding to the
|
||
fully qualified class name of the template instance (typically
|
||
<classname>JdbcTemplate</classname>, but it may be different if you are
|
||
using a custom subclass of the <classname>JdbcTemplate</classname>
|
||
class).</para>
|
||
|
||
<section id="jdbc-JdbcTemplate-examples">
|
||
<title>Examples of JdbcTemplate class usage</title>
|
||
|
||
<para>This section provides some examples of
|
||
<classname>JdbcTemplate</classname> class usage. These examples are
|
||
not an exhaustive list of all of the functionality exposed by the
|
||
<classname>JdbcTemplate</classname>; see the attendant Javadocs for
|
||
that.</para>
|
||
|
||
<section id="jdbc-JdbcTemplate-examples-query">
|
||
<title>Querying (SELECT)</title>
|
||
|
||
<para>Here is a simple query for getting the number of rows in a
|
||
relation:</para>
|
||
|
||
<programlisting language="java">int rowCount = this.jdbcTemplate.queryForInt("select count(*) from t_actor");</programlisting>
|
||
|
||
<para>A simple query using a bind variable:</para>
|
||
|
||
<programlisting language="java">int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt(
|
||
"select count(*) from t_actor where first_name = ?", "Joe");</programlisting>
|
||
|
||
<para>Querying for a <classname>String</classname>:</para>
|
||
|
||
<programlisting language="java">String lastName = this.jdbcTemplate.queryForObject(
|
||
"select last_name from t_actor where id = ?",
|
||
new Object[]{1212L}, String.class);</programlisting>
|
||
|
||
<para>Querying and populating a <emphasis>single</emphasis> domain
|
||
object:</para>
|
||
|
||
<programlisting language="java">Actor actor = this.jdbcTemplate.queryForObject(
|
||
"select first_name, last_name from t_actor where id = ?",
|
||
new Object[]{1212L},
|
||
new RowMapper<Actor>() {
|
||
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
});
|
||
</programlisting>
|
||
|
||
<para>Querying and populating a number of domain objects:</para>
|
||
|
||
<programlisting language="java">List<Actor> actors = this.jdbcTemplate.query(
|
||
"select first_name, last_name from t_actor",
|
||
new RowMapper<Actor>() {
|
||
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
});
|
||
</programlisting>
|
||
|
||
<para>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 <interfacename>RowMapper</interfacename> anonymous inner
|
||
classes, and extract them out into a single class (typically a
|
||
<literal>static</literal> inner class) that can then be referenced
|
||
by DAO methods as needed. For example, it may be better to write the
|
||
last code snippet as follows:</para>
|
||
|
||
<programlisting language="java">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<Actor> {
|
||
|
||
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
}</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-JdbcTemplate-examples-update">
|
||
<title>Updating (INSERT/UPDATE/DELETE) with jdbcTemplate<!--Provide introductory text as with other examples. TR: OK.--></title>
|
||
|
||
<para>You use the <methodname>update(..)</methodname> method to
|
||
perform insert, update and delete operations. Parameter values are
|
||
usually provided as var args or alternatively as an object
|
||
array.</para>
|
||
|
||
<programlisting language="java">this.jdbcTemplate.update(
|
||
"insert into t_actor (first_name, last_name) values (?, ?)",
|
||
"Leonor", "Watling");</programlisting>
|
||
|
||
<programlisting language="java">this.jdbcTemplate.update(
|
||
"update t_actor set = ? where id = ?",
|
||
"Banjo", 5276L);</programlisting>
|
||
|
||
<programlisting language="java">this.jdbcTemplate.update(
|
||
"delete from actor where id = ?",
|
||
Long.valueOf(actorId));</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-JdbcTemplate-examples-other">
|
||
<title>Other jdbcTemplate operations</title>
|
||
|
||
<para>You can use the <methodname>execute(..)</methodname> 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.</para>
|
||
|
||
<programlisting language="java">this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");</programlisting>
|
||
|
||
<para>The following example invokes a simple stored procedure. More
|
||
sophisticated stored procedure support is <link
|
||
linkend="jdbc-StoredProcedure">covered later</link>.</para>
|
||
|
||
<programlisting language="java">this.jdbcTemplate.update(
|
||
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
|
||
Long.valueOf(unionId));</programlisting>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-JdbcTemplate-idioms">
|
||
<title><classname>JdbcTemplate</classname> best practices</title>
|
||
|
||
<para>Instances of the <classname>JdbcTemplate</classname> class are
|
||
<emphasis>threadsafe once configured</emphasis>. This is important
|
||
because it means that you can configure a single instance of a
|
||
<classname>JdbcTemplate</classname> and then safely inject this
|
||
<emphasis>shared</emphasis> reference into multiple DAOs (or
|
||
repositories). The <classname>JdbcTemplate</classname> is stateful, in
|
||
that it maintains a reference to a
|
||
<interfacename>DataSource</interfacename>, but this state is
|
||
<emphasis>not</emphasis> conversational state.</para>
|
||
|
||
<para>A common practice when using the
|
||
<classname>JdbcTemplate</classname> class (and the associated <link
|
||
linkend="jdbc-SimpleJdbcTemplate"><classname>SimpleJdbcTemplate</classname></link>
|
||
and <link
|
||
linkend="jdbc-NamedParameterJdbcTemplate"><classname>NamedParameterJdbcTemplate</classname></link>
|
||
classes) is to configure a <interfacename>DataSource</interfacename>
|
||
in your Spring configuration file, and then dependency-inject that
|
||
shared <interfacename>DataSource</interfacename> bean into your DAO
|
||
classes; the <classname>JdbcTemplate</classname> is created in the
|
||
setter for the <interfacename>DataSource</interfacename>. This leads
|
||
to DAOs that look in part like the following:</para>
|
||
|
||
<programlisting language="java">public class JdbcCorporateEventDao implements CorporateEventDao {
|
||
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
<emphasis role="bold">this.jdbcTemplate = new JdbcTemplate(dataSource);</emphasis>
|
||
}
|
||
|
||
<lineannotation>// JDBC-backed implementations of the methods on the <interfacename>CorporateEventDao</interfacename> follow...</lineannotation>
|
||
}</programlisting>
|
||
|
||
<para>The corresponding configuration might look like this.</para>
|
||
|
||
<programlisting language="xml"><?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">
|
||
|
||
<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></programlisting>
|
||
|
||
<para>An alternative to explicit configuration is to use
|
||
component-scanning and annotation support for dependency injection. In
|
||
this case you annotate the class with
|
||
<interfacename>@Repository</interfacename> (which makes it a candidate
|
||
for component-scanning) and annotate the
|
||
<classname>DataSource</classname> setter method with
|
||
<interfacename>@Autowired</interfacename>.<!--Re preceding sentence, I don't see @Autowired in next two examples. TR: OK AS IS. Made it *bold*--></para>
|
||
|
||
<para><programlisting language="java"><emphasis role="bold">@Repository</emphasis>
|
||
public class JdbcCorporateEventDao implements CorporateEventDao {
|
||
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
<emphasis role="bold">@Autowired</emphasis>
|
||
public void setDataSource(DataSource dataSource) {
|
||
<emphasis role="bold">this.jdbcTemplate = new JdbcTemplate(dataSource);</emphasis>
|
||
}
|
||
|
||
<lineannotation>// JDBC-backed implementations of the methods on the <interfacename>CorporateEventDao</interfacename> follow...</lineannotation>
|
||
}</programlisting></para>
|
||
|
||
<para>The corresponding XML configuration file <!--*corresponding* to what? TR: to the prvious code-snippet-->would
|
||
look like the following:</para>
|
||
|
||
<para><programlisting language="xml"><?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">
|
||
|
||
<!-- 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"/>
|
||
|
||
</beans></programlisting>If you are using Spring's
|
||
<classname>JdbcDaoSupport</classname> class, and your various
|
||
JDBC-backed DAO classes extend from it, then your sub-class inherits a
|
||
<methodname>setDataSource(..)</methodname> method from the
|
||
<classname>JdbcDaoSupport</classname> class. <!--Revise to clarify what you mean by inheriting method *for free*. For free as opposed to what? Also you don't inherit, don't your--><!--subclasses inherit? TR: Revised, please review.-->You
|
||
can choose whether to inherit from this class. The
|
||
<classname>JdbcDaoSupport</classname> class is provided as a
|
||
convenience only.</para>
|
||
|
||
<para>Regardless of which of the above template initialization styles
|
||
you choose to use (or not), it is seldom necessary to create a new
|
||
instance of a <classname>JdbcTemplate</classname> class each time you
|
||
want to execute SQL. Once configured, a
|
||
<classname>JdbcTemplate</classname> instance is threadsafe. You may
|
||
want multiple <classname>JdbcTemplate</classname> instances if your
|
||
application accesses multiple databases, which requires multiple
|
||
<interfacename>DataSources</interfacename>, and subsequently multiple
|
||
differently configured <classname>JdbcTemplates</classname>.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-NamedParameterJdbcTemplate">
|
||
<title><classname>NamedParameterJdbcTemplate</classname></title>
|
||
|
||
<para>The <classname>NamedParameterJdbcTemplate</classname> class adds
|
||
support for programming JDBC statements using named parameters, as
|
||
opposed to programming JDBC statements using only classic placeholder
|
||
(<literal>'?'</literal>) arguments. The
|
||
<classname>NamedParameterJdbcTemplate</classname> class wraps a
|
||
<classname>JdbcTemplate</classname>, and delegates to the wrapped
|
||
<classname>JdbcTemplate</classname> to do much of its work. This section
|
||
describes only those areas of the
|
||
<classname>NamedParameterJdbcTemplate</classname> class that differ from
|
||
the <classname>JdbcTemplate</classname> itself; namely, programming JDBC
|
||
statements using named parameters.</para>
|
||
|
||
<programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
|
||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int countOfActorsByFirstName(String firstName) {
|
||
|
||
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
|
||
|
||
SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
|
||
|
||
return namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
|
||
}</programlisting>
|
||
|
||
<para>Notice the use of the named parameter notation in the value
|
||
assigned to the <literal>sql</literal> variable, and the corresponding
|
||
value that is plugged into the <literal>namedParameters</literal>
|
||
variable (of type <classname>MapSqlParameterSource</classname>).</para>
|
||
|
||
<para>Alternatively, you can pass along named parameters and their
|
||
corresponding values to a
|
||
<classname>NamedParameterJdbcTemplate</classname> instance by using the
|
||
<interfacename>Map</interfacename>-based style.<!--Revision ok? Clarify to say *Alternatively* you can pass along OR *In addition* you can pass along, to clarify whether you can do this--><!--instead of doing what sentence before it says to do, or in addition to doing it. This needs to be clear. TR: OK.-->The
|
||
remaining methods exposed by the
|
||
<interfacename>NamedParameterJdbcOperations</interfacename> and
|
||
implemented by the <classname>NamedParameterJdbcTemplate</classname>
|
||
class follow a similar pattern and are not covered here.</para>
|
||
|
||
<para>The following example shows the use of the
|
||
<interfacename>Map</interfacename>-based style.<!--Need an intro sentence to the following example. What does it show, what's its purpose? TR: OK.--></para>
|
||
|
||
<programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
|
||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int countOfActorsByFirstName(String firstName) {
|
||
|
||
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
|
||
|
||
Map namedParameters = Collections.singletonMap("first_name", firstName);
|
||
|
||
return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
|
||
}</programlisting>
|
||
|
||
<para>One nice feature related to the
|
||
<classname>NamedParameterJdbcTemplate</classname> (and existing in the
|
||
same Java package) is the <classname>SqlParameterSource</classname>
|
||
interface. You have already seen an example of an implementation of this
|
||
interface in one of the previous code snippet (the
|
||
<classname>MapSqlParameterSource</classname> class). <!--Revision ok?Why say *another feature*? So far this is the only feature discussed for NamedParameterJDBC template. It's mentioned above.--><!--In next paragraph you do describe another implementation. --><!--TR: Revised, please review.--><interfacename>An
|
||
<classname>SqlParameterSource</classname></interfacename> is a source of
|
||
named parameter values to a
|
||
<classname>NamedParameterJdbcTemplate</classname>. The
|
||
<classname>MapSqlParameterSource</classname> class is a very simple
|
||
implementation that is simply an adapter around a
|
||
<interfacename>java.util.Map</interfacename>, where the keys are the
|
||
parameter names and the values are the parameter values.</para>
|
||
|
||
<para>Another <interfacename>SqlParameterSource</interfacename>
|
||
implementation is the
|
||
<classname>BeanPropertySqlParameterSource</classname> class. This class
|
||
wraps an arbitrary JavaBean (that is, an instance of a class that
|
||
adheres to <ulink
|
||
url="http://java.sun.com/products/javabeans/docs/spec.html">the JavaBean
|
||
conventions</ulink>), and uses the properties of the wrapped JavaBean as
|
||
the source of named parameter values.</para>
|
||
|
||
<programlisting language="java">public class Actor {
|
||
|
||
private Long id;
|
||
private String firstName;
|
||
private String lastName;
|
||
|
||
public String getFirstName() {
|
||
return this.firstName;
|
||
}
|
||
|
||
public String getLastName() {
|
||
return this.lastName;
|
||
}
|
||
|
||
public Long getId() {
|
||
return this.id;
|
||
}
|
||
|
||
<lineannotation>// setters omitted...</lineannotation>
|
||
|
||
}</programlisting>
|
||
|
||
<programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
|
||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int countOfActors(Actor exampleActor) {
|
||
|
||
<lineannotation>// notice how the named parameters match the properties of the above '<classname>Actor</classname>' class</lineannotation>
|
||
String sql =
|
||
"select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";
|
||
|
||
SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);
|
||
|
||
return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
|
||
}</programlisting>
|
||
|
||
<para>Remember that the
|
||
<classname>NamedParameterJdbcTemplate</classname> class
|
||
<emphasis>wraps</emphasis> a classic <classname>JdbcTemplate</classname>
|
||
template; if you need access to the wrapped
|
||
<classname>JdbcTemplate</classname> instance to access functionality
|
||
only present in the <classname>JdbcTemplate</classname> class, you can
|
||
use the <methodname>getJdbcOperations()</methodname> method to access
|
||
the wrapped <classname>JdbcTemplate</classname> through the
|
||
<interfacename>JdbcOperations</interfacename> interface.</para>
|
||
|
||
<para>See also <xref linkend="jdbc-JdbcTemplate-idioms" /> for
|
||
guidelines on using the
|
||
<classname>NamedParameterJdbcTemplate</classname> class in the context
|
||
of an application.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-SimpleJdbcTemplate">
|
||
<title><classname>SimpleJdbcTemplate</classname></title>
|
||
|
||
<para>The <classname>SimpleJdbcTemplate</classname> class wraps the
|
||
classic <classname>JdbcTemplate</classname> and leverages Java 5
|
||
language features such as varargs and autoboxing.</para>
|
||
|
||
<note>
|
||
<para>In Spring 3.0, the original <classname>JdbcTemplate</classname>
|
||
also supports Java 5-enhanced syntax with generics and varargs.
|
||
However, the <classname>SimpleJdbcTemplate</classname> provides a
|
||
simpler API that works best when you do not need access to all the
|
||
methods that the JdbcTemplate offers. Also, because the
|
||
<classname>SimpleJdbcTemplate</classname> was designed for Java 5, it
|
||
has more methods that take advantage of varargs due to different
|
||
ordering of the parameters.</para>
|
||
</note>
|
||
|
||
<para>The value-add of the <classname>SimpleJdbcTemplate</classname>
|
||
class in the area of syntactic-sugar is best illustrated with a
|
||
before-and-after example. The next code snippet shows data access code
|
||
that uses the classic <classname>JdbcTemplate</classname>, followed by a
|
||
code snippet that does the same job with the
|
||
<classname>SimpleJdbcTemplate</classname>.</para>
|
||
|
||
<programlisting language="java"><lineannotation>// classic <classname>JdbcTemplate</classname>-style...</lineannotation>
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
<!--How is the code shown below different from the code shown in the next example? It seems like they're the same.-->
|
||
public Actor findActor(String specialty, int age) {
|
||
|
||
String sql = "select id, first_name, last_name from T_ACTOR" +
|
||
" where specialty = ? and age = ?";
|
||
|
||
RowMapper<Actor> mapper = new RowMapper<Actor>() {
|
||
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setId(rs.getLong("id"));
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
};
|
||
|
||
|
||
<lineannotation>// notice the wrapping up of the argumenta in an array</lineannotation>
|
||
return (Actor) jdbcTemplate.queryForObject(sql, new Object[] {specialty, age}, mapper);
|
||
}</programlisting>
|
||
|
||
<para>Here is the same method, with the
|
||
<classname>SimpleJdbcTemplate</classname>.<!--The code shown above is the same as the code shown below. What is the difference?
|
||
TR: difference is in the way the parameters are passed in on the last line; no need to use an Objcet[].--></para>
|
||
|
||
<programlisting language="java"><lineannotation>// <classname>SimpleJdbcTemplate</classname>-style...</lineannotation>
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
}
|
||
|
||
public Actor findActor(String specialty, int age) {
|
||
|
||
String sql = "select id, first_name, last_name from T_ACTOR" +
|
||
" where specialty = ? and age = ?";
|
||
RowMapper<Actor> mapper = new RowMapper<Actor>() {
|
||
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setId(rs.getLong("id"));
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
};
|
||
|
||
<lineannotation>// notice the use of varargs since the parameter values now come
|
||
// after the RowMapper parameter</lineannotation>
|
||
return this.simpleJdbcTemplate.queryForObject(sql, mapper, specialty, age);
|
||
}</programlisting>
|
||
|
||
<para>See <xref linkend="jdbc-JdbcTemplate-idioms" /> for guidelines on
|
||
how to use the <classname>SimpleJdbcTemplate</classname> class in the
|
||
context of an application.</para>
|
||
|
||
<note>
|
||
<para>The <classname>SimpleJdbcTemplate</classname> class only offers
|
||
a subset of the methods exposed on the
|
||
<classname>JdbcTemplate</classname> class. If you need to use a method
|
||
from the <classname>JdbcTemplate</classname> that is not defined on
|
||
the <classname>SimpleJdbcTemplate</classname>, you can always access
|
||
the underlying <classname>JdbcTemplate</classname> by calling the
|
||
<methodname>getJdbcOperations()</methodname> method on the
|
||
<classname>SimpleJdbcTemplate</classname>, which then allows you to
|
||
invoke the method that you want. The only downside is that the methods
|
||
on the <interfacename>JdbcOperations</interfacename> interface are not
|
||
generic, so you are back to casting and so on.</para>
|
||
</note>
|
||
</section>
|
||
|
||
<section id="jdbc-SQLExceptionTranslator">
|
||
<title><interfacename>SQLExceptionTranslator</interfacename></title>
|
||
|
||
<para><interfacename>SQLExceptionTranslator</interfacename> is an
|
||
interface to be implemented by classes that can translate between
|
||
<classname>SQLExceptions</classname> and Spring's own
|
||
<classname>org.springframework.dao.DataAccessException</classname>,
|
||
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.</para>
|
||
|
||
<para><classname>SQLErrorCodeSQLExceptionTranslator</classname> is the
|
||
implementation of <interfacename>SQLExceptionTranslator</interfacename>
|
||
that is used by default. This implementation uses specific vendor codes.
|
||
It is more precise than the <literal>SQLState</literal> implementation.
|
||
The error code translations are based on codes held in a JavaBean type
|
||
class called <classname>SQLErrorCodes</classname>. This class is created
|
||
and populated by an <classname>SQLErrorCodesFactory</classname> which as
|
||
the name suggests is a factory for creating
|
||
<classname>SQLErrorCodes</classname> based on the contents of a
|
||
configuration file named <filename
|
||
class="libraryfile">sql-error-codes.xml</filename>. This file is
|
||
populated with vendor codes and based on the
|
||
<code>DatabaseProductName</code> taken from the
|
||
<interfacename>DatabaseMetaData</interfacename>. The codes for the acual
|
||
database you are using are used.<!--what do you mean by *the current* database? --><!--TR: Revised, please review.--></para>
|
||
|
||
<para>The <classname>SQLErrorCodeSQLExceptionTranslator</classname>
|
||
applies matching rules in the following sequence: <!--This reflects sequence in which rules are applied, right? I revised to a numbered list.--><orderedlist
|
||
spacing="compact">
|
||
<note>
|
||
<para>The <classname>SQLErrorCodesFactory</classname> is used by
|
||
default to define Error codes and custom exception translations.
|
||
They are looked up in a file named
|
||
<filename>sql-error-codes.xml</filename> from the classpath and
|
||
the matching <classname>SQLErrorCodes</classname> instance is
|
||
located based on the database name from the database metadata of
|
||
the database in use.</para>
|
||
</note>
|
||
|
||
<listitem>
|
||
<para>Any custom translation implemented by a subclass. Normally
|
||
the provided concrete
|
||
<classname>SQLErrorCodeSQLExceptionTranslator</classname> is used
|
||
so this rule does not apply. It only applies if you have actually
|
||
provided a subclass implementation.<!--Pls revise last sentence to clarify. *Which* class is concrete? Why do you first refer to a subclass, then say *this class* is--><!--typically used and thus rule does not apply? This is really confusing.--><!--TR: Revised, please review.--></para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Any custom implementation of the
|
||
<classname>SQLExceptionTranslator</classname> interface that is
|
||
provided as the
|
||
<classname>customSqlExceptionTranslator</classname> property of
|
||
the <classname>SQLErrorCodes</classname> class.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>The list of instances of the
|
||
<classname>CustomSQLErrorCodesTranslation</classname> class,
|
||
provided for the <classname>customTranslations</classname>
|
||
property of the <classname>SQLErrorCodes</classname> class, are
|
||
searched for a match.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Error code matching is applied.<!--Wording of the next sentence does not track. Please revise. --><!--TR: Revised, please review.--></para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Use the fallback translator.
|
||
<classname>SQLExceptionSubclassTranslator</classname> is the
|
||
default fallback translator. If this translation is not available
|
||
then the next fallback translator is the
|
||
<classname>SQLStateSQLExceptionTranslator</classname>.</para>
|
||
</listitem>
|
||
</orderedlist></para>
|
||
|
||
<para>You can extend
|
||
<classname>SQLErrorCodeSQLExceptionTranslator:</classname></para>
|
||
|
||
<programlisting language="java">public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
|
||
|
||
protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
|
||
if (sqlex.getErrorCode() == -12345) {
|
||
return new DeadlockLoserDataAccessException(task, sqlex);
|
||
}
|
||
return null;
|
||
}
|
||
}</programlisting>
|
||
|
||
<para>In this example, the specific error code <literal>-12345</literal>
|
||
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 <classname>JdbcTemplate</classname> through
|
||
the method <literal>setExceptionTranslator</literal> and to use this
|
||
<classname>JdbcTemplate</classname> for all of the data access
|
||
processing where this translator is needed. Here is an example of how
|
||
this custom translator can be used:</para>
|
||
|
||
<programlisting language="java"><lineannotation>private JdbcTemplate jdbcTemoplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
// create a <classname>JdbcTemplate</classname> and set data source</lineannotation>
|
||
this.jdbcTemplate = new JdbcTemplate();
|
||
this.jdbcTemplate.setDataSource(dataSource);
|
||
<lineannotation> // create a custom translator and set the <interfacename>DataSource</interfacename> for the default translation lookup</lineannotation>
|
||
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
|
||
tr.setDataSource(dataSource);
|
||
this.jdbcTemplate.setExceptionTranslator(tr);
|
||
}
|
||
|
||
<lineannotation>public void updateShippingCharge(long orderId, long pct) {
|
||
// use the <classname>prepared JdbcTemplate</classname> for this u<classname>pdate</classname></lineannotation>
|
||
this.jdbcTemplate.update(
|
||
"update orders" +
|
||
" set shipping_charge = shipping_charge * ? / 100" +
|
||
" where id = ?"
|
||
pct, orderId);
|
||
}</programlisting>
|
||
|
||
<para>The custom translator is passed a data source in order to look up
|
||
the error codes in <literal>sql-error-codes.xml</literal>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-statements-executing">
|
||
<title>Executing statements</title>
|
||
|
||
<para>Executing an SQL statement requires very little code. You need a
|
||
<interfacename>DataSource</interfacename> and a
|
||
<classname>JdbcTemplate</classname>, including the convenience
|
||
methods<!--Does reader know what you mean by *convenience* methods? TR: OK as is. I hope they know what this is.-->
|
||
that are provided with the <classname>JdbcTemplate</classname>. The
|
||
following example shows what you need to include for a minimal but fully
|
||
functional class that creates a new table:</para>
|
||
|
||
<programlisting language="java">import javax.sql.DataSource;
|
||
import org.springframework.jdbc.core.JdbcTemplate;
|
||
|
||
public class ExecuteAStatement {
|
||
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
|
||
public void doExecute() {
|
||
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
|
||
}
|
||
}</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-statements-querying">
|
||
<title>Running queries</title>
|
||
|
||
<para>Some query methods return a single value. To retrieve a count or a
|
||
specific value from one row, use
|
||
<methodname>queryForInt(..)</methodname>,
|
||
<methodname>queryForLong(..)</methodname> or
|
||
<methodname>queryForObject(..)</methodname>. The latter converts the
|
||
returned JDBC <classname>Type</classname> to the Java class that is
|
||
passed in as an argument. If the type conversion is invalid, then an
|
||
<exceptionname>InvalidDataAccessApiUsageException</exceptionname> is
|
||
thrown. Here is an example that contains two query methods, one for an
|
||
<classname>int</classname> and one that queries for a
|
||
<classname>String</classname>.</para>
|
||
|
||
<programlisting language="java">import javax.sql.DataSource;
|
||
import org.springframework.jdbc.core.JdbcTemplate;
|
||
|
||
public class RunAQuery {
|
||
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int getCount() {
|
||
return this.jdbcTemplate.queryForInt("select count(*) from mytable");
|
||
}
|
||
|
||
public String getName() {
|
||
return (String) this.jdbcTemplate.queryForObject("select name from mytable", String.class);
|
||
}
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.dataSource = dataSource;
|
||
}
|
||
}</programlisting>
|
||
|
||
<para>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 <methodname>queryForList(..)</methodname> which
|
||
returns a <interfacename>List</interfacename> where each entry is a
|
||
<interfacename>Map</interfacename> with each entry in the map
|
||
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:</para>
|
||
|
||
<programlisting language="java">
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
|
||
public List<Map<String, Object>> getList() {
|
||
return this.jdbcTemplate.queryForList("select * from mytable");
|
||
}</programlisting>
|
||
|
||
<para>The list returned would look something like this:</para>
|
||
|
||
<programlisting>[{name=Bob, id=1}, {name=Mary, id=2}]</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-updates">
|
||
<title>Updating the database</title>
|
||
|
||
<para>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.</para>
|
||
|
||
<programlisting language="java">import javax.sql.DataSource;
|
||
|
||
import org.springframework.jdbc.core.JdbcTemplate;
|
||
|
||
public class ExecuteAnUpdate {
|
||
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
|
||
public void setName(int id, String name) {
|
||
this.jdbcTemplate.update(
|
||
"update mytable set name = ? where id = ?",
|
||
name, id);
|
||
}
|
||
}</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-auto-genereted-keys">
|
||
<title>Retrieving auto-generated keys</title>
|
||
|
||
<para>An <methodname>update()</methodname> convenience method supports<!--Give name of this method. Also indicate *what* is acquiring the primary keys. TR: Changed to *retrieval*.
|
||
The name of the method is *update*.--> 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
|
||
<classname>PreparedStatementCreator</classname> as its first argument,
|
||
and this is the way the required insert statement is specified. The
|
||
other argument is a <classname>KeyHolder</classname>, which contains the
|
||
generated key on successful return from the update. There is not a
|
||
standard single way to create an appropriate
|
||
<classname>PreparedStatement</classname> (which explains why the method
|
||
signature is the way it is). The following example works on Oracle but
|
||
may not work on other platforms:</para>
|
||
|
||
<programlisting language="java">final String INSERT_SQL = "insert into my_test (name) values(?)";
|
||
final String name = "Rob";
|
||
|
||
KeyHolder keyHolder = new GeneratedKeyHolder();
|
||
jdbcTemplate.update(
|
||
new PreparedStatementCreator() {
|
||
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
|
||
PreparedStatement ps =
|
||
connection.prepareStatement(INSERT_SQL, new String[] {"id"});
|
||
ps.setString(1, name);
|
||
return ps;
|
||
}
|
||
},
|
||
keyHolder);
|
||
|
||
<lineannotation>// keyHolder.getKey() now contains the generated key</lineannotation></programlisting>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-connections">
|
||
<title>Controlling database connections</title>
|
||
|
||
<section id="jdbc-datasource">
|
||
<title><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.--></title>
|
||
|
||
<para>Spring obtains a connection to the database through a
|
||
<interfacename>DataSource</interfacename>. A
|
||
<interfacename>DataSource</interfacename> 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.</para>
|
||
|
||
<para>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.</para>
|
||
|
||
<para>This section uses Spring's
|
||
<classname>DriverManagerDataSource</classname> implementation, and
|
||
several additional implementations are covered later.</para>
|
||
|
||
<para><note>
|
||
<para>Only use the <classname>DriverManagerDataSource</classname>
|
||
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.</para>
|
||
</note>You obtain a connection with
|
||
<classname>DriverManagerDataSource</classname> as you typically obtain a
|
||
JDBC connection. Specify the fully qualified classname of the JDBC
|
||
driver so that the <classname>DriverManager</classname> 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
|
||
<classname>DriverManagerDataSource</classname> in Java code:</para>
|
||
|
||
<programlisting language="java">DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
|
||
dataSource.setUsername("sa");
|
||
dataSource.setPassword("");</programlisting>
|
||
|
||
<para>Here is the corresponding XML configuration:</para>
|
||
|
||
<programlisting language="java"><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"/></programlisting>
|
||
|
||
<para>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.</para>
|
||
|
||
<para>DBCP configuration:</para>
|
||
|
||
<programlisting language="java"><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"/></programlisting>
|
||
|
||
<para>C3P0 configuration:</para>
|
||
|
||
<programlisting language="java"><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"/></programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-DataSourceUtils">
|
||
<title><classname>DataSourceUtils</classname></title>
|
||
|
||
<para>The <classname>DataSourceUtils</classname> class is a convenient
|
||
and powerful helper class that provides <literal>static</literal>
|
||
methods to obtain connections from JNDI and close connections if
|
||
necessary. It supports thread-bound connections with, for example,
|
||
<classname>DataSourceTransactionManager</classname>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-SmartDataSource">
|
||
<title><interfacename>SmartDataSource</interfacename></title>
|
||
|
||
<para>The <interfacename>SmartDataSource</interfacename> interface
|
||
should be implemented by classes that can provide a connection to a
|
||
relational database. It extends the
|
||
<interfacename>DataSource</interfacename> 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.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-AbstractDataSource">
|
||
<title><classname>AbstractDataSource</classname></title>
|
||
|
||
<para><code><classname>AbstractDataSource</classname></code> is an
|
||
<literal><classname>abstract</classname></literal> base class for
|
||
Spring's <interfacename>DataSource</interfacename> implementations that
|
||
implements code that is common to all <classname>DataSource</classname>
|
||
implementations.<!--Please revise *takes care of uninteresting glue* to specify what exactly it does. Avoid slang and idomatic language, --><!--especially important with non-native English readers. TR: Revised, please review.-->
|
||
You extend the <classname>AbstractDataSource</classname> class if you
|
||
are writing your own <interfacename>DataSource</interfacename>
|
||
implementation.<!--Preceding revision ok? If not, revise to specify *which* class you extend if you are writing your own DataSource imp. TR: OK.--></para>
|
||
</section>
|
||
|
||
<section id="jdbc-SingleConnectionDataSource">
|
||
<title><classname>SingleConnectionDataSource</classname></title>
|
||
|
||
<para>The <classname>SingleConnectionDataSource</classname> class is an
|
||
implementation of the <interfacename>SmartDataSource</interfacename>
|
||
interface that wraps a <emphasis>single</emphasis>
|
||
<interfacename>Connection</interfacename> that is
|
||
<emphasis>not</emphasis> closed after each use. Obviously, this is not
|
||
multi-threading capable.</para>
|
||
|
||
<para>If any client code calls <command>close</command> in the
|
||
assumption of a pooled connection, as when using persistence tools, set
|
||
the <literal>suppressClose</literal> property to
|
||
<literal>true</literal>. <!--Have I revised this correctly? THe client code is calling *close*? If not, revise to clarify. Also WHERE do you set --><!--suppressClose to true? TR: OK. suppressClose is set directly on the SingleConnectionDataSource instance.-->This
|
||
setting returns a close-suppressing proxy wrapping the physical
|
||
connection. Be aware that you will not be able to cast this<!--this *what*?-->
|
||
to a native Oracle <interfacename>Connection</interfacename> or the like
|
||
anymore.</para>
|
||
|
||
<para>This is primarily a test class. For example, it enables easy
|
||
testing of code outside an application server, in conjunction with a
|
||
simple JNDI environment. In contrast to
|
||
<classname>DriverManagerDataSource</classname>, it reuses the same
|
||
connection all the time, avoiding excessive creation of physical
|
||
connections.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-DriverManagerDataSource">
|
||
<title><classname>DriverManagerDataSource</classname></title>
|
||
|
||
<para>The <classname>DriverManagerDataSource</classname> class is an
|
||
implementation of the standard <interfacename>DataSource</interfacename>
|
||
interface that configures a plain JDBC driver through bean properties,
|
||
and returns a new <interfacename>Connection</interfacename> every
|
||
time.</para>
|
||
|
||
<para>This implementation is useful for test and stand-alone
|
||
environments outside of a Java EE container, either as a
|
||
<interfacename>DataSource</interfacename> bean in a Spring IoC
|
||
container, or in conjunction with a simple JNDI environment.
|
||
Pool-assuming <literal>Connection.close()</literal> calls will simply
|
||
close the connection, so any
|
||
<interfacename>DataSource</interfacename>-aware persistence code should
|
||
work. However, using JavaBean-style connection pools such as
|
||
<code>commons-dbcp</code> is so easy, even in a test environment, that
|
||
it is almost always preferable to use such a connection pool over
|
||
<classname>DriverManagerDataSource</classname>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-TransactionAwareDataSourceProxy">
|
||
<title><classname>TransactionAwareDataSourceProxy</classname></title>
|
||
|
||
<para><classname>TransactionAwareDataSourceProxy</classname> is a proxy
|
||
for a target <interfacename>DataSource</interfacename>, which wraps that
|
||
target <interfacename>DataSource</interfacename> to add awareness of
|
||
Spring-managed transactions. In this respect, it is similar to a
|
||
transactional JNDI <interfacename>DataSource</interfacename> as provided
|
||
by a Java EE server.</para>
|
||
|
||
<note>
|
||
<para>It is rarely desirable to use this class, except when already
|
||
existing code that must be called and passed a standard JDBC
|
||
<interfacename>DataSource</interfacename> 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.
|
||
<!--Clarify preceding sentence. Are you saying, if you use TransactionAwareDataSource Proxy in this case, then what?--><!--I don't get the *usable, but* participating in Spring-managed transactions. TR: Revised, please review. -->It
|
||
is generally preferable to write your own new code using the higher
|
||
level abstractions for resource management, such as
|
||
<classname>JdbcTemplate</classname> or
|
||
<classname>DataSourceUtils</classname>.</para>
|
||
</note>
|
||
|
||
<para><emphasis>(See the
|
||
<classname>TransactionAwareDataSourceProxy</classname> Javadocs for more
|
||
details.)</emphasis></para>
|
||
</section>
|
||
|
||
<section id="jdbc-DataSourceTransactionManager">
|
||
<title><classname>DataSourceTransactionManager</classname></title>
|
||
|
||
<para>The <classname>DataSourceTransactionManager</classname> class is a
|
||
<interfacename>PlatformTransactionManager</interfacename> implementation
|
||
for single JDBC datasources. It binds a JDBC connection from the
|
||
specified data source to the currently executing thread, potentially
|
||
allowing for one thread connection per data source.</para>
|
||
|
||
<para>Application code is required <!--app code such as what, for example? What do you have to provide? TR: OK as is.-->to
|
||
retrieve the JDBC connection through
|
||
<literal>DataSourceUtils.getConnection(DataSource)</literal> instead of
|
||
Java EE's standard <literal>DataSource.getConnection</literal>. It
|
||
throws unchecked <literal>org.springframework.dao</literal> exceptions
|
||
instead of checked <exceptionname>SQLExceptions</exceptionname>. All
|
||
framework classes like <classname>JdbcTemplate</classname> 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.</para>
|
||
|
||
<para>The <classname>DataSourceTransactionManager</classname> 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 <classname>JdbcTemplate</classname> or
|
||
call the <literal>DataSourceUtils.applyTransactionTimeout(..)</literal>
|
||
method for each created statement.</para>
|
||
|
||
<para>This implementation can be used instead of
|
||
<classname>JtaTransactionManager</classname> 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. JTA does not support custom
|
||
isolation levels!</para>
|
||
</section>
|
||
|
||
<section id="jdbc-NativeJdbcExtractor">
|
||
<title>NativeJdbcExtractor</title>
|
||
|
||
<para>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
|
||
<classname>DataSource</classname> that wraps the
|
||
<classname>Connection</classname>, <classname>Statement</classname> and
|
||
<classname>ResultSet</classname> objects with its own wrapper objects.
|
||
To gain access to the native objects you can configure your
|
||
<classname>JdbcTemplate</classname> or
|
||
<classname>OracleLobHandler</classname> with a
|
||
<classname>NativeJdbcExtractor</classname>.</para>
|
||
|
||
<para>The <code>NativeJdbcExtractor</code> comes in a variety of flavors
|
||
to match your execution environment:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>SimpleNativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>C3P0NativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>CommonsDbcpNativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>JBossNativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>WebLogicNativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>WebSphereNativeJdbcExtractor</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>XAPoolNativeJdbcExtractor</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<para>Usually the <classname>SimpleNativeJdbcExtractor</classname> is
|
||
sufficient for unwrapping a <classname>Connection</classname> object in
|
||
most environments. See the Javadocs for more details.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-advanced-jdbc">
|
||
<title>JDBC batch operations</title>
|
||
|
||
<para>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 covers batch
|
||
processing using both the <classname>JdbcTemplate</classname> and the
|
||
<classname>SimpleJdbcTemplate</classname>.</para>
|
||
|
||
<section id="jdbc-advanced-classic">
|
||
<title>Batch operations with the JdbcTemplate</title>
|
||
|
||
<para>You accomplish <classname>JdbcTemplate</classname> batch
|
||
processing by implementing two methods of a special interface,
|
||
<classname>BatchPreparedStatementSetter</classname>, and passing that in
|
||
as the second parameter in your <classname>batchUpdate</classname>
|
||
method call. Use the <classname>getBatchSize</classname> method to
|
||
provide the size of the current batch. Use the
|
||
<classname>setValues</classname> 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
|
||
<classname>getBatchSize</classname> 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:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private JdbcTemplate jdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int[] batchUpdate(final List<Actor> actors) {
|
||
int[] updateCounts = jdbcTemplate.batchUpdate(
|
||
"update t_actor set first_name = ?, last_name = ? where id = ?",
|
||
new BatchPreparedStatementSetter() {
|
||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||
ps.setString(1, actors.get(i).getFirstName());
|
||
ps.setString(2, actors.get(i).getLastName());
|
||
ps.setLong(3, actors.get(i).getId().longValue());
|
||
}
|
||
|
||
public int getBatchSize() {
|
||
return actors.size();
|
||
}
|
||
} );
|
||
return updateCounts;
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>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
|
||
<classname>InterruptibleBatchPreparedStatementSetter</classname>
|
||
interface, which allows you to interrupt a batch once the input source
|
||
is exhausted. The <classname>isBatchExhausted</classname> method allows
|
||
you to signal the end of the batch.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-advanced-simple">
|
||
<title>Batch operations with the SimpleJdbcTemplate</title>
|
||
|
||
<para>The <classname>SimpleJdbcTemplate</classname> provides an
|
||
alternate way of providing the batch update. Instead of implementing a
|
||
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
|
||
<classname>SqlParameterSource</classname>, one entry for each member of
|
||
the batch. You can use the
|
||
<classname>SqlParameterSource.createBatch</classname> method to create
|
||
this array, passing in either an array of JavaBeans or an array of Maps
|
||
containing the parameter values.</para>
|
||
|
||
<para>This example shows a batch update using named parameters:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
}
|
||
|
||
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",
|
||
batch);
|
||
return updateCounts;
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>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.</para>
|
||
|
||
<para>The same example using classic JDBC "?" placeholders:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
}
|
||
|
||
public int[] batchUpdate(final List<Actor> actors) {
|
||
List<Object[]> batch = new ArrayList<Object[]>();
|
||
for (Actor actor : actors) {
|
||
Object[] values = new Object[] {
|
||
actor.getFirstName(),
|
||
actor.getLastName(),
|
||
actor.getId()};
|
||
batch.add(values);
|
||
}
|
||
int[] updateCounts = simpleJdbcTemplate.batchUpdate(
|
||
"update t_actor set first_name = ?, last_name = ? where id = ?",
|
||
batch);
|
||
return updateCounts;
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>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.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc">
|
||
<title>Simplifying JDBC operations with the SimpleJdbc classes</title>
|
||
|
||
<para>The <classname>SimpleJdbcInsert</classname> and
|
||
<classname>SimpleJdbcCall</classname> classes provide a simplified
|
||
configuration by taking advantage of database metadata that can be
|
||
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.</para>
|
||
|
||
<section id="jdbc-simple-jdbc-insert-1">
|
||
<title>Inserting data using SimpleJdbcInsert</title>
|
||
|
||
<para>Let's start by looking at the
|
||
<classname>SimpleJdbcInsert</classname> class with the minimal amount of
|
||
configuration options. You should instantiate the
|
||
<classname>SimpleJdbcInsert</classname> in the data access layer's
|
||
initialization method. <!--What do you mean *should be*? Are you saying a human should do it. If so, say *You should instantiate the SimpleJdbcInsert...* Also, is--><!--it correct to say *in* the data access layer's init method? Should it be *with*. Below, what do you mean by *fluid style*?
|
||
TR: Revised, please review.-->For this example, the initializing method is the
|
||
<classname>setDataSource</classname> method. You do not need to subclass
|
||
the <classname>SimpleJdbcInsert</classname> class; simply create a new
|
||
instance and set the table name using the
|
||
<classname>withTableName</classname> method. Configuration methods for
|
||
this class follow the "fluid" style that returns the instance of the
|
||
<classname>SimpleJdbcInsert</classname>, which allows you to chain all
|
||
configuration methods. This example uses only one configuration method;
|
||
you will see examples of multiple ones later.</para>
|
||
|
||
<programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcInsert insertActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.insertActor =
|
||
new SimpleJdbcInsert(dataSource).withTableName("t_actor");
|
||
}
|
||
|
||
public void add(Actor actor) {
|
||
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());
|
||
insertActor.execute(parameters);
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>
|
||
|
||
<para>The execute method used here takes a plain
|
||
<classname>java.utils.Map</classname> as its only parameter. The
|
||
important thing to note here is that the keys used for the Map must
|
||
match the column names of the table as defined in the database. This is
|
||
because we read the metadata in order to construct the actual insert
|
||
statement.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-insert-2">
|
||
<title>Retrieving auto-generated keys using SimpleJdbcInsert</title>
|
||
|
||
<para>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
|
||
<classname>SimpleJdbcInsert</classname>, in addition to specifying the
|
||
table name, you specify the name of the generated key column with the
|
||
<classname>usingGeneratedKeyColumns</classname> method.</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcInsert insertActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.insertActor =
|
||
new SimpleJdbcInsert(dataSource)
|
||
.withTableName("t_actor")
|
||
.usingGeneratedKeyColumns("id");
|
||
}
|
||
|
||
public void add(Actor actor) {
|
||
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);
|
||
actor.setId(newId.longValue());
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>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
|
||
<literal>executeReturningKey</literal> method. This returns a
|
||
<literal>java.lang.Number</literal> 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;
|
||
<literal>java.lang.Number</literal> 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 <literal>KeyHolder</literal> that is
|
||
returned from the <literal>executeReturningKeyHolder</literal>
|
||
method.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-insert-3">
|
||
<title>Specifying columns for a SimpleJdbcInsert</title>
|
||
|
||
<para>You can limit the columns for an insert by specifying a list of
|
||
column names with the <classname>usingColumns</classname> method:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcInsert insertActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.insertActor =
|
||
new SimpleJdbcInsert(dataSource)
|
||
.withTableName("t_actor")
|
||
.usingColumns("first_name", "last_name")
|
||
.usingGeneratedKeyColumns("id");
|
||
}
|
||
|
||
public void add(Actor actor) {
|
||
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);
|
||
actor.setId(newId.longValue());
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>The execution of the insert is the same as if you had relied
|
||
on the metadata to determine which columns to use.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-parameters">
|
||
<title>Using SqlParameterSource to provide parameter values</title>
|
||
|
||
<para>Using a <classname>Map</classname> to provide parameter values
|
||
works fine, but it's not the most convenient class to use. Spring
|
||
provides a couple of implementations of the
|
||
<classname>SqlParameterSource</classname> interface that can be used
|
||
instead.<!--But *what* class (classname?) is not the most convenient? TR: OK as is.-->The
|
||
first one is <classname>BeanPropertySqlParameterSource</classname>,
|
||
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:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcInsert insertActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.insertActor =
|
||
new SimpleJdbcInsert(dataSource)
|
||
.withTableName("t_actor")
|
||
.usingGeneratedKeyColumns("id");
|
||
}
|
||
|
||
public void add(Actor actor) {
|
||
SqlParameterSource parameters = new BeanPropertySqlParameterSource(actor);
|
||
Number newId = insertActor.executeAndReturnKey(parameters);
|
||
actor.setId(newId.longValue());
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>Another option is the
|
||
<classname>MapSqlParameterSource</classname> that resembles a Map but
|
||
provides a more convenient <classname>addValue</classname> method that
|
||
can be chained.</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcInsert insertActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.insertActor =
|
||
new SimpleJdbcInsert(dataSource)
|
||
.withTableName("t_actor")
|
||
.usingGeneratedKeyColumns("id");
|
||
}
|
||
|
||
public void add(Actor actor) {
|
||
SqlParameterSource parameters = new MapSqlParameterSource()
|
||
.addValue("first_name", actor.getFirstName())
|
||
.addValue("last_name", actor.getLastName());
|
||
Number newId = insertActor.executeAndReturnKey(parameters);
|
||
actor.setId(newId.longValue());
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>As you can see, the configuration is the same; only the
|
||
executing code has to change to use these alternative input
|
||
classes.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-call-1">
|
||
<title>Calling a stored procedure with SimpleJdbcCall</title>
|
||
|
||
<para>The <classname>SimpleJdbcCall</classname> class leverages metadata
|
||
in the database to look up names of <code>in</code> and <code>out</code>
|
||
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 <code>ARRAY</code> or <code>STRUCT</code> that do not have an
|
||
automatic mapping to a Java class. The first example shows a simple
|
||
procedure that returns only scalar values in <code>VARCHAR</code> and
|
||
<code>DATE</code> format from a MySQL database. The example procedure
|
||
reads a specified actor entry and returns <code>first_name</code>,
|
||
<code>last_name</code>, and <code>birth_date</code> columns in the form
|
||
of <code>out</code> parameters.</para>
|
||
|
||
<para><programlisting>CREATE PROCEDURE read_actor (
|
||
IN in_id INTEGER,
|
||
OUT out_first_name VARCHAR(100),
|
||
OUT out_last_name VARCHAR(100),
|
||
OUT out_birth_date DATE)
|
||
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;</programlisting>The <code>in_id</code> parameter contains the
|
||
<code>id</code> of the actor you are looking up. The <code>out</code>
|
||
parameters return the data read from the table.</para>
|
||
|
||
<para>The <classname>SimpleJdbcCall</classname> is declared in a similar
|
||
manner to the <classname>SimpleJdbcInsert</classname>. You should
|
||
instantiate and configure the class in the initialization method of your
|
||
data access layer. Compared to the StoredProcedure 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. <!--Reword preceding: You need not subclass *what?* and you declare *what* in init method? TR: Revised, pplease review.-->Following
|
||
is an example of a SimpleJdbcCall configuration using the above stored
|
||
procedure. The only configuration option, in addition to the
|
||
<classname>DataSource</classname>, is the name of the stored
|
||
procedure.<!--Indicate what the purpose of this example is (what it does) and identify the name of procedure. Also see next query. TR: Revised, please review.--></para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcCall procReadActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
this.procReadActor =
|
||
new SimpleJdbcCall(dataSource)
|
||
.withProcedureName("read_actor");
|
||
}
|
||
|
||
public Actor readActor(Long id) {
|
||
SqlParameterSource in = new MapSqlParameterSource()
|
||
.addValue("in_id", id);
|
||
Map out = procReadActor.execute(in);
|
||
Actor actor = new Actor();
|
||
actor.setId(id);
|
||
actor.setFirstName((String) out.get("out_first_name"));
|
||
actor.setLastName((String) out.get("out_last_name"));
|
||
actor.setBirthDate((Date) out.get("out_birth_date"));
|
||
return actor;
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>The code you write for the execution of the call involves
|
||
creating an <classname>SqlParameterSource</classname> containing the IN
|
||
parameter. <!--sentence before this one said *all you need to specify* is name of procedure, but preceding sentence says it involves creating an--><!--SQLParameterSource. Isn't this *in addition* to specifying procedure name? Revise to clarify what a human does in this example. --><!--Reword preceding to clarify whether a human creates the SqlParameterSource.
|
||
TR: Revised, please review. Execution is separate from declaration, so we still only need to declare the name of the proc.-->It's
|
||
important to match the name provided for the input value with that of
|
||
the parameter name <!--match *what* to the name of parameter in stored procedure?? And if this is something you're telling a human to do,--><!--reword to say *You must match <what> to the name of the parameter etc* TR: Revised.-->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.</para>
|
||
|
||
<para>The <classname>execute</classname> method takes the IN parameters
|
||
and returns a Map containing any <code>out</code> parameters keyed by
|
||
the name as specified in the stored procedure. In this case they are
|
||
<classname>out_first_name, out_last_name</classname> and
|
||
<classname>out_birth_date</classname>.</para>
|
||
|
||
<para>The last part of the <classname>execute</classname> method creates
|
||
an Actor instance to use to return the data retrieved. Again, it is
|
||
important to use the names of the <code>out</code> parameters as they
|
||
are declared in the stored procedure. <!--*match* them how? What are you matching to what? I see three different out parameters (first name, last name, birth date). Revise. TR: Revised.-->Also,
|
||
the case in the names of the <code>out</code> parameters stored in the
|
||
results map matches that of the <code>out</code> parameter names in the
|
||
database, which could vary between databases. <!--Preceding sentence, are you saying the case will match, or it *should*? Next sentence, state why you are doing what you are told to do. TR: Revised.-->To
|
||
make your code more portable you should do a case-insensitive lookup or
|
||
instruct Spring to use a <classname>CaseInsensitiveMap</classname> from
|
||
the Jakarta Commons project. To do the latter, you create your own
|
||
<classname>JdbcTemplate</classname> and set the
|
||
<classname>setResultsMapCaseInsensitive</classname> property to
|
||
<classname>true</classname>. Then you pass this customized
|
||
<classname>JdbcTemplate</classname> instance into the constructor of
|
||
your <classname>SimpleJdbcCall</classname>. You must include the
|
||
<classname>commons-collections.jar</classname> in your classpath for
|
||
this to work. Here is an example of this configuration:</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcCall procReadActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
|
||
jdbcTemplate.setResultsMapCaseInsensitive(true);
|
||
this.procReadActor =
|
||
new SimpleJdbcCall(jdbcTemplate)
|
||
.withProcedureName("read_actor");
|
||
}
|
||
|
||
|
||
// ... additional methods
|
||
}</programlisting>By taking this action, you avoid conflicts in the case used
|
||
for the names of your returned <code>out</code> parameters.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-call-2">
|
||
<title>Explicitly declaring parameters to use for a
|
||
SimpleJdbcCall</title>
|
||
|
||
<para>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 <classname>SimpleJdbcCall</classname> with the
|
||
<classname>declareParameters</classname> method, which takes a variable
|
||
number of <classname>SqlParameter</classname> objects as input. See the
|
||
next section for details on how to define an
|
||
<classname>SqlParameter</classname>.<!--Moved following info from end of section and made it a note. Important to know this up front. TR: OK.--></para>
|
||
|
||
<para><note>
|
||
<para>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.</para>
|
||
</note></para>
|
||
|
||
<para>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. <!--Is my rewording of preceding sentence ok? (See next sentence.)-->To
|
||
bypass all processing of metadata lookups for potential parameters and
|
||
only use the declared parameters, you call the method
|
||
<classname>withoutProcedureColumnMetaDataAccess</classname> 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
|
||
<classname>useInParameterNames</classname> to specify the list of IN
|
||
parameter names to include for a given signature.</para>
|
||
|
||
<para>The following example shows a fully declared procedure call, using
|
||
the information from the preceding example.</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcCall procReadActor;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
|
||
jdbcTemplate.setResultsMapCaseInsensitive(true);
|
||
this.procReadActor =
|
||
new SimpleJdbcCall(jdbcTemplate)
|
||
.withProcedureName("read_actor")
|
||
.withoutProcedureColumnMetaDataAccess()
|
||
.useInParameterNames("in_id")
|
||
.declareParameters(
|
||
new SqlParameter("in_id", Types.NUMERIC),
|
||
new SqlOutParameter("out_first_name", Types.VARCHAR),
|
||
new SqlOutParameter("out_last_name", Types.VARCHAR),
|
||
new SqlOutParameter("out_birth_date", Types.DATE)
|
||
);
|
||
}
|
||
|
||
|
||
// ... additional methods
|
||
}</programlisting>The execution and end results of the two examples are the
|
||
same; this one specifies all details explicitly rather than relying on
|
||
metadata.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-params">
|
||
<title>How to define SqlParameters</title>
|
||
|
||
<para>To define a parameter for the SimpleJdbc classes and also for the
|
||
RDBMS operations classes, covered in <xref linkend="jdbc-object" />,
|
||
<!--Deleted *described in following section* because RDBMS not mentioned in next section (5.8). Revise to give link to section you mean.-->you
|
||
use an <classname>SqlParameter</classname> or one of its subclasses. You
|
||
typically specify the parameter name and SQL type in the constructor.
|
||
The SQL type is specified using the
|
||
<classname>java.sql.Types</classname> constants. We have already seen
|
||
declarations like:</para>
|
||
|
||
<para><programlisting language="java"> new SqlParameter("in_id", Types.NUMERIC),
|
||
new SqlOutParameter("out_first_name", Types.VARCHAR),</programlisting></para>
|
||
|
||
<para>The first line with the <classname>SqlParameter</classname>
|
||
declares an IN parameter. IN parameters can be used for both stored
|
||
procedure calls and for queries using the
|
||
<classname>SqlQuery</classname> and its subclasses covered in the
|
||
following section.</para>
|
||
|
||
<para>The second line with the <classname>SqlOutParameter</classname>
|
||
declares an <code>out</code> parameter to be used in a stored procedure
|
||
call. There is also an <classname>SqlInOutParameter</classname> for
|
||
<code>InOut</code> parameters, parameters that provide an
|
||
<code>IN</code> value to the procedure and that also return a
|
||
value.</para>
|
||
|
||
<note>
|
||
<para>Only parameters declared as <classname>SqlParameter</classname>
|
||
and <classname>SqlInOutParameter</classname> will be used to provide
|
||
input values. This is different from the
|
||
<classname>StoredProcedure</classname> class, which for backwards
|
||
compatibility reasons allows input values to be provided for
|
||
parameters declared as <classname>SqlOutParameter</classname>.</para>
|
||
</note>
|
||
|
||
<para>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 <code>out</code> parameters, you can provide a
|
||
<classname>RowMapper</classname> to handle mapping of rows returned from
|
||
a <code>REF</code> cursor. Another option is to specify an
|
||
<classname>SqlReturnType</classname> that provides an opportunity to
|
||
define customized handling of the return values.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-call-3">
|
||
<title>Calling a stored function using SimpleJdbcCall</title>
|
||
|
||
<para>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 <classname>withFunctionName</classname>
|
||
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,
|
||
<classname>executeFunction,</classname> 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. <!--Are you saying you use withFunctionName, *then* use executeFunction? OR do you use one *or* the other? revise to clarify. Second --><!--snippet below uses both. TR: Revised.-->A
|
||
similar convenience method named <classname>executeObject</classname> is
|
||
also available for stored procedures that only have one <code>out</code>
|
||
parameter. The following example is based on a stored function named
|
||
<classname>get_actor_name</classname> that returns an actor's full name.
|
||
Here is the MySQL source for this function:</para>
|
||
|
||
<para><programlisting>CREATE FUNCTION get_actor_name (in_id INTEGER)
|
||
RETURNS VARCHAR(200) READS SQL DATA
|
||
BEGIN
|
||
DECLARE out_name VARCHAR(200);
|
||
SELECT concat(first_name, ' ', last_name)
|
||
INTO out_name
|
||
FROM t_actor where id = in_id;
|
||
RETURN out_name;
|
||
END;</programlisting></para>
|
||
|
||
<para>To call this function we again create a
|
||
<classname>SimpleJdbcCall</classname> in the initialization
|
||
method.</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcCall funcGetActorName;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
|
||
jdbcTemplate.setResultsMapCaseInsensitive(true);
|
||
this.funcGetActorName =
|
||
new SimpleJdbcCall(jdbcTemplate)
|
||
.withFunctionName("get_actor_name");
|
||
}
|
||
|
||
public String getActorName(Long id) {
|
||
SqlParameterSource in = new MapSqlParameterSource()
|
||
.addValue("in_id", id);
|
||
String name = funcGetActorName.executeFunction(String.class, in);
|
||
return name;
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>The execute method <!--In paragraph before first example it refers to executeFunction; is this what you mean by execute method? TR: Yes.-->used
|
||
returns a <classname>String</classname> containing the return value from
|
||
the function call.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-simple-jdbc-call-4">
|
||
<title>Returning ResultSet/REF Cursor from a SimpleJdbcCall</title>
|
||
|
||
<para>Calling a stored procedure or function that returns a result set
|
||
is a bit tricky. Some databases return result sets during the JDBC
|
||
results processing while others require an explicitly registered
|
||
<code>out</code> parameter of a specific type. Both approaches need
|
||
additional processing to loop over the result set and process the
|
||
returned rows. With the <classname>SimpleJdbcCall</classname> you use
|
||
the <classname>returningResultSet</classname> method and declare a
|
||
<classname>RowMapper</classname> 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 in which you declare the
|
||
<classname>RowMapper</classname> 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.</para>
|
||
|
||
<para>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:</para>
|
||
|
||
<para><programlisting>CREATE PROCEDURE read_all_actors()
|
||
BEGIN
|
||
SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a;
|
||
END;</programlisting>To call this procedure you declare the
|
||
<classname>RowMapper</classname>. Because the class you want to map to
|
||
follows the JavaBean rules, you can use a
|
||
<classname>ParameterizedBeanPropertyRowMapper</classname> that is
|
||
created by passing in the required class to map to in the
|
||
<classname>newInstance</classname> method.</para>
|
||
|
||
<para><programlisting language="java">public class JdbcActorDao implements ActorDao {
|
||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||
private SimpleJdbcCall procReadAllActors;
|
||
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
|
||
jdbcTemplate.setResultsMapCaseInsensitive(true);
|
||
this.procReadAllActors =
|
||
new SimpleJdbcCall(jdbcTemplate)
|
||
.withProcedureName("read_all_actors")
|
||
.returningResultSet("actors",
|
||
ParameterizedBeanPropertyRowMapper.newInstance(Actor.class));
|
||
}
|
||
|
||
public List getActorsList() {
|
||
Map m = procReadAllActors.execute(new HashMap<String, Object>(0));
|
||
return (List) m.get("actors");
|
||
}
|
||
|
||
// ... additional methods
|
||
}</programlisting>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.</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-object">
|
||
<title>Modeling JDBC operations as Java objects</title>
|
||
|
||
<para>The <literal>org.springframework.jdbc.object</literal> package
|
||
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.</para>
|
||
|
||
<note>
|
||
<para>Many Spring developers believe that the various RDBMS operation
|
||
classes described below (with the exception of the <link
|
||
linkend="jdbc-StoredProcedure"><classname>StoredProcedure</classname></link>
|
||
class) can often be replaced with straight
|
||
<classname>JdbcTemplate</classname> calls. Often it is simpler to write
|
||
a DAO method that simply calls a method on a
|
||
<classname>JdbcTemplate</classname> directly (as opposed to
|
||
encapsulating a query as a full-blown class).<!--I don't know how the second sentence in the note is supposed to read, and whether it suggests something different--><!--from what the Spring developers suggest, or is it the same thing? Clarify. TR: Revised.--></para>
|
||
|
||
<para>However, if you are getting measurable value from using the RDBMS
|
||
operation classes, continue using these classes.</para>
|
||
</note>
|
||
|
||
<section id="jdbc-SqlQuery">
|
||
<title><classname>SqlQuery</classname></title>
|
||
|
||
<para><classname>SqlQuery</classname> is a reusable, threadsafe class
|
||
that encapsulates an SQL query. Subclasses must implement the
|
||
<methodname>newRowMapper(..)</methodname> method to provide a
|
||
<interfacename>RowMapper</interfacename> instance that can create one
|
||
object per row obtained from iterating over the
|
||
<interfacename>ResultSet</interfacename> that is created during the
|
||
execution of the query. The <classname>SqlQuery</classname> class is
|
||
rarely used directly because the <classname>MappingSqlQuery</classname>
|
||
subclass provides a much more convenient implementation for mapping rows
|
||
to Java classes. Other implementations that extend
|
||
<classname>SqlQuery</classname> are
|
||
<classname>MappingSqlQueryWithParameters</classname> and
|
||
<classname>UpdatableSqlQuery</classname>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-MappingSqlQuery">
|
||
<title><classname>MappingSqlQuery</classname></title>
|
||
|
||
<para><classname>MappingSqlQuery</classname> is a reusable query in
|
||
which concrete subclasses must implement the abstract
|
||
<methodname>mapRow(..)</methodname> method to convert each row of the
|
||
supplied <interfacename>ResultSet</interfacename> into an object of the
|
||
type specified. The following example shows a custom query that maps the
|
||
data from the <code>t_actor</code> relation to an instance of the
|
||
<classname>Actor</classname> class.</para>
|
||
|
||
<programlisting language="java">public class ActorMappingQuery extends MappingSqlQuery<Actor> {
|
||
|
||
public ActorMappingQuery(DataSource ds) {
|
||
super(ds, "select id, first_name, last_name from t_actor where id = ?");
|
||
super.declareParameter(new SqlParameter("id", Types.INTEGER));
|
||
compile();
|
||
}
|
||
|
||
@Override
|
||
protected Actor mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||
Actor actor = new Actor();
|
||
actor.setId(rs.getLong("id"));
|
||
actor.setFirstName(rs.getString("first_name"));
|
||
actor.setLastName(rs.getString("last_name"));
|
||
return actor;
|
||
}
|
||
|
||
}</programlisting>
|
||
|
||
<para>The class extends <classname>MappingSqlQuery</classname>
|
||
parameterized with the <classname>Actor</classname> type. The
|
||
constructor for this customer query takes the
|
||
<interfacename>DataSource</interfacename> as the only parameter. In this
|
||
constructor you call the constructor on the superclass with the
|
||
<interfacename>DataSource</interfacename> and the SQL that should be
|
||
executed to retrieve the rows for this query. This SQL will be used to
|
||
create a <interfacename>PreparedStatement</interfacename> so it may
|
||
contain place holders for any parameters to be passed in during
|
||
execution.<!--Identify *it*. PreparedStatement? TR: It's a common Java JDBC class.-->You
|
||
must declare each parameter using the
|
||
<literal>declareParameter</literal> method passing in an
|
||
<classname>SqlParameter</classname>. <!--Rewording ok? Whenever you say that X *must* happen, it usually involves human interaction to make X happen or do something to --><!--make X happen. TR: Revised.-->The
|
||
<classname>SqlParameter</classname> takes a name and the JDBC type as
|
||
defined in <classname>java.sql.Types</classname>. After you define all
|
||
parameters, you call the <literal>compile()</literal> 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<!--beginning of sentence says *this class*, then it says *these classes*. Are you talking about one class or multiple classes. Revise. TR: Revised.-->
|
||
are created when the DAO is initialized they can be kept as instance
|
||
variables and be reused.</para>
|
||
|
||
<programlisting language="java">private ActorMappingQuery actorMappingQuery;
|
||
|
||
@Autowired
|
||
public void setDataSource(DataSource dataSource) {
|
||
this.actorMappingQuery = new ActorMappingQuery(dataSource);
|
||
}
|
||
|
||
public Customer getCustomer(Long id) {
|
||
return actorMappingQuery.findObject(id);
|
||
}</programlisting>
|
||
|
||
<para>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 <code>findObject</code>
|
||
with the id as parameter. If we had instead a query that 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.</para>
|
||
|
||
<programlisting language="java">public List<Actor> searchForActors(int age, String namePattern) {
|
||
List<Actor> actors = actorSearchMappingQuery.execute(age, namePattern);
|
||
return actors;
|
||
}</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-SqlUpdate">
|
||
<title><classname>SqlUpdate</classname></title>
|
||
|
||
<para>The <classname>SqlUpdate</classname> class encapsulates an SQL
|
||
update. Like a query, an update object is reusable, and like all
|
||
<classname>RdbmsOperation</classname> classes, an update can have
|
||
parameters and is defined in SQL. This class provides a number of
|
||
<methodname>update(..)</methodname> methods analogous to the
|
||
<methodname>execute(..)</methodname> methods of query objects. The
|
||
<classname>SQLUpdate</classname> 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
|
||
<classname>execute</classname>. <!--I have broken the preceding line and next line into two sentences, but they still don't read right. What do you mean by *where we call it--><!--execute*? That doesn't make sense. Also, avoid *we*, say *you*. TR: revised.-->However,
|
||
you don't have to subclass the <classname>SqlUpdate</classname> class
|
||
since it can easily be parameterized by setting SQL and declaring
|
||
parameters.<!--Revise *parameterized*; this is not a word. And, what is the point being made? Rewrite this sentence and the one before it. TR: OK.--></para>
|
||
|
||
<programlisting language="java">import java.sql.Types;
|
||
|
||
import javax.sql.DataSource;
|
||
|
||
import org.springframework.jdbc.core.SqlParameter;
|
||
import org.springframework.jdbc.object.SqlUpdate;
|
||
|
||
public class UpdateCreditRating extends SqlUpdate {
|
||
|
||
public UpdateCreditRating(DataSource ds) {
|
||
setDataSource(ds);
|
||
setSql("update customer set credit_rating = ? where id = ?");
|
||
declareParameter(new SqlParameter("creditRating", Types.NUMERIC));
|
||
declareParameter(new SqlParameter("id", Types.NUMERIC));
|
||
compile();
|
||
}
|
||
|
||
/**
|
||
* @param id for the Customer to be updated
|
||
* @param rating the new value for credit rating
|
||
* @return number of rows updated
|
||
*/
|
||
public int execute(int id, int rating) {
|
||
return update(rating, id);
|
||
}
|
||
}</programlisting>
|
||
</section>
|
||
|
||
<section id="jdbc-StoredProcedure">
|
||
<title><classname>StoredProcedure</classname></title>
|
||
|
||
<para>The <classname>StoredProcedure</classname> class is a superclass
|
||
for object abstractions of RDBMS stored procedures. This class is
|
||
<literal>abstract</literal>, and its various
|
||
<literal>execute(..)</literal> methods have <literal>protected</literal>
|
||
access, preventing use other than through a subclass that offers tighter
|
||
typing.</para>
|
||
|
||
<para>The inherited <literal>sql</literal> property will be the name of
|
||
the stored procedure in the RDBMS.</para>
|
||
|
||
<para>To define a parameter for the
|
||
<classname>StoredProcedure</classname> class, you use an
|
||
<classname>SqlParameter</classname> 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
|
||
<classname>java.sql.Types</classname> constants.<!--The following example shows what, what is its purpose? TR: Revised.--></para>
|
||
|
||
<para><programlisting language="java"> new SqlParameter("in_id", Types.NUMERIC),
|
||
new SqlOutParameter("out_first_name", Types.VARCHAR),</programlisting></para>
|
||
|
||
<para>The first line with the <classname>SqlParameter</classname>
|
||
declares an IN parameter. IN parameters can be used for both stored
|
||
procedure calls and for queries using the
|
||
<classname>SqlQuery</classname> and its subclasses covered in the
|
||
following section.</para>
|
||
|
||
<para>The second line with the <classname>SqlOutParameter</classname>
|
||
declares an <code>out</code> parameter to be used in the stored
|
||
procedure call. There is also an
|
||
<classname>SqlInOutParameter</classname> for
|
||
<code>I</code><code>nOut</code> parameters, parameters that provide an
|
||
<code>in</code> value to the procedure and that also return a
|
||
value.</para>
|
||
|
||
<para>For <code>i</code><code>n</code> 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 <code>out</code> parameters you
|
||
can provide a <classname>RowMapper</classname> to handle mapping of rows
|
||
returned from a REF cursor. Another option is to specify an
|
||
<classname>SqlReturnType</classname> that enables you to define
|
||
customized handling of the return values.</para>
|
||
|
||
<para>Here is an example of a simple DAO that uses a
|
||
<classname>StoredProcedure</classname> to call a function,
|
||
<literal>sysdate()</literal>,which comes with any Oracle database. To
|
||
use the stored procedure functionality you have to create a class that
|
||
extends <classname>StoredProcedure</classname>. In this example, the
|
||
<classname>StoredProcedure</classname> class is an inner class, but if
|
||
you need to reuse the <classname>StoredProcedure</classname> 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
|
||
<classname>SqlOutParameter</classname>. The <literal>execute()</literal>
|
||
method executes the procedure and extracts the returned date from the
|
||
results <classname>Map</classname>. The results
|
||
<classname>Map</classname> has an entry for each declared output
|
||
parameter, in this case only one, using the parameter name as the
|
||
key.</para>
|
||
|
||
<programlisting language="java">import java.sql.Types;
|
||
import java.util.Date;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
import javax.sql.DataSource;
|
||
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.jdbc.core.SqlOutParameter;
|
||
import org.springframework.jdbc.object.StoredProcedure;
|
||
|
||
public class StoredProcedureDao {
|
||
|
||
private GetSysdateProcedure getSysdate;
|
||
|
||
@Autowired
|
||
public void init(DataSource dataSource) {
|
||
this.getSysdate = new GetSysdateProcedure(dataSource);
|
||
}
|
||
|
||
public Date getSysdate() {
|
||
return getSysdate.execute();
|
||
}
|
||
|
||
private class GetSysdateProcedure extends StoredProcedure {
|
||
|
||
private static final String SQL = "sysdate";
|
||
|
||
public GetSysdateProcedure(DataSource dataSource) {
|
||
setDataSource(dataSource);
|
||
setFunction(true);
|
||
setSql(SQL);
|
||
declareParameter(new SqlOutParameter("date", Types.DATE));
|
||
compile();
|
||
}
|
||
|
||
public Date execute() {
|
||
// the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
|
||
Map<String, Object> results = execute(new HashMap<String, Object>());
|
||
Date sysdate = (Date) results.get("date");
|
||
return sysdate;
|
||
}
|
||
}
|
||
|
||
}</programlisting>
|
||
|
||
<para>The following example of a <classname>StoredProcedure</classname>
|
||
has two output parameters (in this case, Oracle REF cursors).</para>
|
||
|
||
<programlisting language="java">import oracle.jdbc.OracleTypes;
|
||
import org.springframework.jdbc.core.SqlOutParameter;
|
||
import org.springframework.jdbc.object.StoredProcedure;
|
||
|
||
import javax.sql.DataSource;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
public class TitlesAndGenresStoredProcedure extends StoredProcedure {
|
||
|
||
private static final String SPROC_NAME = "AllTitlesAndGenres";
|
||
|
||
public TitlesAndGenresStoredProcedure(DataSource dataSource) {
|
||
super(dataSource, SPROC_NAME);
|
||
declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper()));
|
||
declareParameter(new SqlOutParameter("genres", OracleTypes.CURSOR, new GenreMapper()));
|
||
compile();
|
||
}
|
||
|
||
public Map<String, Object> execute() {
|
||
// again, this sproc has no input parameters, so an empty Map is supplied
|
||
return super.execute(new HashMap<String, Object>());
|
||
}
|
||
}</programlisting>
|
||
|
||
<para>Notice how the overloaded variants of the
|
||
<literal>declareParameter(..)</literal> method that have been used in
|
||
the <classname>TitlesAndGenresStoredProcedure</classname> constructor
|
||
are passed <interfacename>RowMapper</interfacename> implementation
|
||
instances; this is a very convenient and powerful way to reuse existing
|
||
functionality. The code for the two
|
||
<interfacename>RowMapper</interfacename> implementations is provided
|
||
below.</para>
|
||
|
||
<para>The <classname>TitleMapper</classname> class maps a
|
||
<interfacename>ResultSet</interfacename> to a
|
||
<classname>Title</classname> domain object for each row in the supplied
|
||
<interfacename>ResultSet</interfacename>:</para>
|
||
|
||
<programlisting language="java">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<Title> {
|
||
|
||
public Title mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
Title title = new Title();
|
||
title.setId(rs.getLong("id"));
|
||
title.setName(rs.getString("name"));
|
||
return title;
|
||
}
|
||
}</programlisting>
|
||
|
||
<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">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 Genre mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||
return new Genre(rs.getString("name"));
|
||
}
|
||
}</programlisting>
|
||
|
||
<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">import oracle.jdbc.OracleTypes;
|
||
import org.springframework.jdbc.core.SqlOutParameter;
|
||
import org.springframework.jdbc.core.SqlParameter;
|
||
import org.springframework.jdbc.object.StoredProcedure;
|
||
|
||
import javax.sql.DataSource;
|
||
|
||
import java.sql.Types;
|
||
import java.util.Date;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
public class TitlesAfterDateStoredProcedure extends StoredProcedure {
|
||
|
||
private static final String SPROC_NAME = "TitlesAfterDate";
|
||
private static final String CUTOFF_DATE_PARAM = "cutoffDate";
|
||
|
||
public TitlesAfterDateStoredProcedure(DataSource dataSource) {
|
||
super(dataSource, SPROC_NAME);
|
||
declareParameter(new SqlParameter(CUTOFF_DATE_PARAM, Types.DATE);
|
||
declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper()));
|
||
compile();
|
||
}
|
||
|
||
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>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-parameter-handling">
|
||
<title>Common problems with parameter and data value handling</title>
|
||
|
||
<para>Common problems with parameters and data values exist in the
|
||
different approaches provided by the Spring Framework JDBC.</para>
|
||
|
||
<section id="jdbc-type-information">
|
||
<title>Providing SQL type information for parameters</title>
|
||
|
||
<para>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.</para>
|
||
|
||
<para>You can provide SQL type information in several ways:</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>Many update and query methods of the
|
||
<classname>JdbcTemplate</classname> take an additional parameter in
|
||
the form of an <code>int </code>array. This array is used to
|
||
indicate the SQL type of the coresponding parameter using constant
|
||
values from the <classname>java.sql.Types</classname> class. <!--Reword to say *what* is using constant values from the java.sql.Types class to do *what*. Phrases that being with *using* are --><!--often unclear as to what uses what to do what.-->Provide
|
||
one entry for each parameter.</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>You can use the <classname>SqlParameterValue</classname> class
|
||
to wrap the parameter value that needs this additional information.
|
||
<!--I revised another unclear case of *using*. If it's not correct, revise to say what is using the SqlParameterValue class to do what. TR: OK.-->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.</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>For methods working with named parameters, use the
|
||
<classname>SqlParameterSource</classname> classes
|
||
<classname>BeanPropertySqlParameterSource</classname> or
|
||
<classname>MapSqlParameterSource</classname>. They both have methods
|
||
for registering the SQL type for any of the named parameter
|
||
values.</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section id="jdbc-lob">
|
||
<title>Handling BLOB and CLOB objects</title>
|
||
|
||
<para>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 <code>SimpleJdbc</code> classes. All
|
||
of these approaches use an implementation of the
|
||
<classname>LobHandler</classname> interface for the actual management of
|
||
the LOB data. The <classname>LobHandler</classname> provides access to a
|
||
<classname>LobCreator</classname> class, through the
|
||
<classname>getLobCreator</classname> method, used for creating new LOB
|
||
objects to be inserted.</para>
|
||
|
||
<para>The <classname>LobCreator/LobHandler</classname> provides the
|
||
following support for LOB input and output:</para>
|
||
|
||
<para><itemizedlist>
|
||
<listitem>
|
||
<para>BLOB</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>byte[] – getBlobAsBytes and setBlobAsBytes</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>InputStream – getBlobAsBinaryStream and
|
||
setBlobAsBinaryStream</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</listitem>
|
||
</itemizedlist><itemizedlist>
|
||
<listitem>
|
||
<para>CLOB</para>
|
||
|
||
<itemizedlist>
|
||
<listitem>
|
||
<para>String – getClobAsString and setClobAsString</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>InputStream – getClobAsAsciiStream and
|
||
setClobAsAsciiStream</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Reader – getClobAsCharacterStream and
|
||
setClobAsCharacterStream</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</listitem>
|
||
</itemizedlist></para>
|
||
|
||
<para>The next example shows how to create and insert a BLOB. Later you
|
||
will see how to read it back from the database.</para>
|
||
|
||
<para>This example uses a <code>JdbcTemplate</code> and an
|
||
implementation of the
|
||
<code>AbstractLobCreatingPreparedStatementCallbac</code><code>k</code>.
|
||
It implements one method, <code>setValues</code>. This method provides a
|
||
<code>LobCreator</code> that you use to set the values for the LOB
|
||
columns in your SQL insert statement.</para>
|
||
|
||
<para>For this example we assume that there is a variable,
|
||
<code>lobHandle</code><code>r</code>, that already is set to an instance
|
||
of a <classname>DefaultLobHandler</classname>. You typically set this
|
||
value through dependency injection.<!--Rewording ok? (What does what through dependency injection?) TR: Revised.--></para>
|
||
|
||
<programlistingco>
|
||
<areaspec>
|
||
<area coords="8" id="jdbc.lobhandler.variableref" />
|
||
|
||
<area coords="12" id="jdbc.lobhandler.setClob" />
|
||
|
||
<area coords="13" id="jdbc.lobhandler.setBlob" />
|
||
</areaspec>
|
||
|
||
<programlisting language="java">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);
|
||
final InputStreamReader clobReader = new InputStreamReader(clobIs);
|
||
jdbcTemplate.execute(
|
||
"INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)",
|
||
new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
|
||
protected void setValues(PreparedStatement ps, LobCreator lobCreator)
|
||
throws SQLException {
|
||
ps.setLong(1, 1L);
|
||
lobCreator.setClobAsCharacterStream(ps, 2, clobReader, (int)clobIn.length());
|
||
lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, (int)blobIn.length());
|
||
}
|
||
}
|
||
);
|
||
blobIs.close();
|
||
clobReader.close();</programlisting>
|
||
|
||
<calloutlist>
|
||
<callout arearefs="jdbc.lobhandler.variableref">
|
||
<para>Pass in the lobHandler that in this example is a plain
|
||
<classname>DefaultLobHandler</classname><!--*Here* where?(deleted *Here we*) I don't see this in example.Use the lobHandler to do what? TR: Revised.--></para>
|
||
</callout>
|
||
|
||
<callout arearefs="jdbc.lobhandler.setClob">
|
||
<para>Using the method
|
||
<classname>setClobAsCharacterStream</classname>, pass in the
|
||
contents of the CLOB.</para>
|
||
</callout>
|
||
|
||
<callout arearefs="jdbc.lobhandler.setBlob">
|
||
<para>Using the method
|
||
<classname>setBlobAsBinaryStream</classname>, pass in the contents
|
||
of the BLOB.</para>
|
||
</callout>
|
||
</calloutlist>
|
||
</programlistingco>
|
||
|
||
<para>Now it's time to read the LOB data from the database. Again, you
|
||
use a <code>JdbcTemplate</code> with the same instance variable
|
||
<code>l</code><code>obHandler </code>and a reference to a
|
||
<classname>DefaultLobHandler</classname>.</para>
|
||
|
||
<para><programlistingco>
|
||
<areaspec>
|
||
<area coords="5" id="jdbc.lobhandler.getClob" />
|
||
|
||
<area coords="7" id="jdbc.lobhandler.getBlob" />
|
||
</areaspec>
|
||
|
||
<programlisting language="java">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");
|
||
results.put("BLOB", blobBytes);
|
||
return results;
|
||
}
|
||
});
|
||
</programlisting>
|
||
|
||
<calloutlist>
|
||
<callout arearefs="jdbc.lobhandler.setClob">
|
||
<para>Using the method <classname>getClobAsString,
|
||
</classname>retrieve the contents of the CLOB.</para>
|
||
</callout>
|
||
|
||
<callout arearefs="jdbc.lobhandler.setBlob">
|
||
<para>Using the method <classname>getBlobAsBytes,</classname>
|
||
retrieve the contents of the BLOB.<!--MISSING THE NUMBER 2 IN SNIPPET ABOVE. ADD WHERE APPROPRIATE. TR: ?; OK AS IS.--></para>
|
||
</callout>
|
||
</calloutlist>
|
||
</programlistingco></para>
|
||
</section>
|
||
|
||
<section id="jdbc-in-clause">
|
||
<title>Passing in lists of values for IN clause</title>
|
||
|
||
<para>The SQL standard allows for selecting rows based on an expression
|
||
that includes a variable list of values. A typical example would be
|
||
<code>select * from T_ACTOR where id in (1, 2, 3)</code>. 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 <classname>NamedParameterJdbcTemplate</classname> and
|
||
<classname>SimpleJdbcTemplate</classname> takes the latter approach.
|
||
Pass in the values as a <classname>java.util.List</classname> of
|
||
primitive objects. This list will be used to insert the required
|
||
placeholders and pass in the values during the statement
|
||
execution.</para>
|
||
|
||
<note>
|
||
<para>Be careful when passing in many values. The JDBC standard does
|
||
not guarantee that you can use more than 100 values for an
|
||
<code>in</code> 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.</para>
|
||
</note>
|
||
|
||
<para>In addition to the primitive values in the value list, you can
|
||
create a <classname>java.util.List</classname> of object arrays. This
|
||
list would support multiple expressions defined for the <code>in</code>
|
||
clause such as <code>select * from T_ACTOR where (id, last_name) in
|
||
((1, 'Johnson'), (2, 'Harrop'))</code>. This
|
||
of course requires that your database supports this syntax.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-complex-types">
|
||
<title>Handling complex types for stored procedure calls</title>
|
||
|
||
<para>When you call stored procedures you can sometimes use complex
|
||
types specific to the database. To accommodate these types, Spring
|
||
provides a <classname>SqlReturnType</classname> for handling them when
|
||
they are returned from the stored procedure call and
|
||
<classname>SqlTypeValue</classname> when they are passed in as a
|
||
parameter to the stored procedure.</para>
|
||
|
||
<para>Here is an example of returning the value of an Oracle
|
||
<code>STRUCT</code> object of the user declared type
|
||
<code>ITEM_TYPE</code>. The <classname>SqlReturnType</classname>
|
||
interface has a single method named <classname>getTypeValue</classname>
|
||
that must be implemented. This interface is used as part of the
|
||
declaration of an <classname>SqlOutParameter</classname>.</para>
|
||
|
||
<para><programlisting language="java">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",
|
||
new SqlReturnType() {
|
||
public Object getTypeValue(CallableStatement cs, int colIndx, int sqlType, String typeName)
|
||
throws SQLException {
|
||
STRUCT struct = (STRUCT)cs.getObject(colIndx);
|
||
Object[] attr = struct.getAttributes();
|
||
TestItem item = new TestItem();
|
||
item.setId(((Number) attr[0]).longValue());
|
||
item.setDescription((String)attr[1]);
|
||
item.setExpirationDate((java.util.Date)attr[2]);
|
||
return item;
|
||
}
|
||
}));</programlisting>You use the <classname>SqlTypeValue</classname> to
|
||
pass in the value of a Java object like <classname>TestItem</classname>
|
||
into a stored procedure. <!--Revise preceding as necessary. What do you mean by *go[ing] from Java to the database*? Is that the right way to say it? TR: Revised.-->The
|
||
<classname>SqlTypeValue</classname> interface has a single method named
|
||
<classname>createTypeValue</classname> that you must implement. The
|
||
active connection is passed in, and you can use it to create
|
||
database-specific objects such as
|
||
<classname>StructDescriptor</classname>s, as shown in the following
|
||
example, or <classname>ArrayDescriptor</classname>s.<!--Rewording of preceding ok? The example is showing human participation, I assume. ;-) TR: Yes :), OK.--></para>
|
||
|
||
<para><programlisting language="java">final TestItem - new TestItem(123L, "A test item",
|
||
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"););
|
||
|
||
SqlTypeValue value = new AbstractSqlTypeValue() {
|
||
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
|
||
StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn);
|
||
Struct item = new STRUCT(itemDescriptor, conn,
|
||
new Object[] {
|
||
testItem.getId(),
|
||
testItem.getDescription(),
|
||
new java.sql.Date(testItem.getExpirationDate().getTime())
|
||
});
|
||
return item;
|
||
}
|
||
};</programlisting>This <classname>SqlTypeValue</classname> can now be added
|
||
to the Map containing the input parameters for the execute call of the
|
||
stored procedure.</para>
|
||
|
||
<para>Another use for the <classname>SqlTypeValue</classname> is passing
|
||
in an array of values to an Oracle stored procedure. Oracle has its own
|
||
internal <classname>ARRAY</classname> class that must be used in this
|
||
case, and you can use the <classname>SqlTypeValue</classname> to create
|
||
an instance of the Oracle <classname>ARRAY</classname> and populate it
|
||
with values from the Java <code>ARRAY</code>.</para>
|
||
|
||
<programlisting language="java">final Long[] ids = new Long[] {1L, 2L};
|
||
|
||
SqlTypeValue value = new AbstractSqlTypeValue() {
|
||
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
|
||
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
|
||
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
|
||
return idArray;
|
||
}
|
||
};</programlisting>
|
||
</section>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-support">
|
||
<title>Embedded database support</title>
|
||
|
||
<para>The <literal>org.springframework.jdbc.datasource.embedded</literal>
|
||
package provides support for embedded Java database engines. Support for
|
||
<ulink url="http://www.hsqldb.org">HSQL</ulink>, <ulink
|
||
url="http://www.h2database.com">H2</ulink>, and <ulink
|
||
url="http://db.apache.org/derby">Derby</ulink> is provided natively. You
|
||
can also use an extensible API to plug in new embedded database types and
|
||
<classname>DataSource</classname> implementations.</para>
|
||
|
||
<section id="jdbc-why-embedded-database">
|
||
<title>Why use an embedded database?</title>
|
||
|
||
<para>An embedded database is useful during the development phase of a
|
||
project because of its lightweight nature. Benefits include ease of
|
||
configuration, quick startup time, testability, and the ability to
|
||
rapidly evolve SQL during development.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-xml">
|
||
<title>Creating an embedded database instance using Spring XML</title>
|
||
|
||
<para>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: <programlisting language="xml"> <jdbc:embedded-database id="dataSource">
|
||
<jdbc:script location="classpath:schema.sql"/>
|
||
<jdbc:script location="classpath:test-data.sql"/>
|
||
</jdbc:embedded-database>
|
||
</programlisting></para>
|
||
|
||
<para>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 <classname>javax.sql.DataSource</classname>.
|
||
This bean can then be injected into data access objects as
|
||
needed.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-java">
|
||
<title>Creating an embedded database instance programmatically</title>
|
||
|
||
<para>The <classname>EmbeddedDatabaseBuilder</classname> 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:
|
||
<programlisting language="java"> EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||
EmbeddedDatabase db = builder.setType(H2).addScript("my-schema.sql").addScript("my-test-data.sql").build();
|
||
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
|
||
db.shutdown()
|
||
</programlisting></para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-extension">
|
||
<title>Extending the embedded database support</title>
|
||
|
||
<para>Spring JDBC embedded database support can be extended in two ways:
|
||
<orderedlist>
|
||
<listitem>
|
||
<para>Implement <classname>EmbeddedDatabaseConfigurer</classname>
|
||
to support a new embedded database type, such as Apache
|
||
Derby.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Implement <classname>DataSourceFactory</classname> to
|
||
support a new DataSource implementation, such as a connection
|
||
pool, to manage embedded database connections.</para>
|
||
</listitem>
|
||
</orderedlist></para>
|
||
|
||
<para>You are encouraged to contribute back extensions to the Spring
|
||
community at <ulink
|
||
url="jira.springframework.org">jira.springframework.org</ulink>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-using-HSQL">
|
||
<title>Using HSQL</title>
|
||
|
||
<para>Spring supports HSQL 1.8.0 and above. HSQL is the default embedded
|
||
database if no type is specified explicitly. To specify HSQL explicitly,
|
||
set the <literal>type</literal> attribute of the
|
||
<literal>embedded-database</literal> tag to <literal>HSQL</literal>. If
|
||
you are using the builder API, call the
|
||
<literal>setType(EmbeddedDatabaseType)</literal> method with
|
||
<literal>EmbeddedDatabaseType.HSQL</literal>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-using-H2">
|
||
<title>Using H2</title>
|
||
|
||
<para>Spring supports the H2 database as well. To enable H2, set the
|
||
<literal>type</literal> attribute of the
|
||
<literal>embedded-database</literal> tag to <literal>H2</literal>. If
|
||
you are using the builder API, call the
|
||
<literal>setType(EmbeddedDatabaseType)</literal> method with
|
||
<literal>EmbeddedDatabaseType.H2</literal>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-using-Derby">
|
||
<title>Using Derby</title>
|
||
|
||
<para>Spring also supports Apache Derby 10.5 and above. To enable Derby,
|
||
set the <literal>type</literal> attribute of the
|
||
<literal>embedded-database</literal> tag to <literal>Derby</literal>. If
|
||
using the builder API, call the
|
||
<literal>setType(EmbeddedDatabaseType)</literal> method with
|
||
<literal>EmbeddedDatabaseType.Derby</literal>.</para>
|
||
</section>
|
||
|
||
<section id="jdbc-embedded-database-dao-testing">
|
||
<title>Testing data access logic with an embedded database</title>
|
||
|
||
<para>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:</para>
|
||
|
||
<programlisting language="java">
|
||
public class DataAccessUnitTestTemplate {
|
||
private EmbeddedDatabase db;
|
||
|
||
@Before
|
||
public void setUp() {
|
||
// creates a HSQL in-memory db populated from default scripts classpath:schema.sql and classpath:test-data.sql
|
||
db = new EmbeddedDatabaseBuilder().addDefaultScripts().build();
|
||
}
|
||
|
||
@Test
|
||
public void testDataAccess() {
|
||
JdbcTemplate template = new JdbcTemplate(db);
|
||
template.query(...);
|
||
}
|
||
|
||
@After
|
||
public void tearDown() {
|
||
db.shutdown();
|
||
}
|
||
}
|
||
</programlisting>
|
||
</section>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Initializing a DataSource</title>
|
||
|
||
<para>The <literal>org.springframework.jdbc.datasource.init</literal>
|
||
package provides support for initializing an existing
|
||
<classname>DataSource</classname>. The embedded database support provides
|
||
one option for creating and initializing a
|
||
<classname>DataSource</classname> for an application, but sometimes you
|
||
need to initialize an instance running on a server somewhere.</para>
|
||
|
||
<section>
|
||
<title>Initializing a database instance using Spring XML</title>
|
||
|
||
<para>If you want to initialize a database and you can provide a
|
||
reference to a DataSource bean, use the
|
||
<literal>initialize-database</literal> tag in the
|
||
<literal>spring-jdbc</literal> namespace:</para>
|
||
|
||
<programlisting><jdbc:initialize-database data-source="dataSource">
|
||
<jdbc:script location="classpath:com/foo/sql/db-schema.sql"/>
|
||
<jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/>
|
||
</jdbc:initialize-database></programlisting>
|
||
|
||
<para>The example above runs the two scripts specified against the
|
||
database: the first script is a schema creation, and the second is a
|
||
test data set insert. The script locations can also be patterns with
|
||
wildcards in the usual ant style used for resources in Spring (e.g.
|
||
<code>classpath*:/com/foo/**/sql/*-data.sql</code>). If a pattern is
|
||
used the scripts are executed in lexical order of their URL or
|
||
filename.</para>
|
||
|
||
<para>The default behaviour of the database initializer is to
|
||
unconditionally execute the scripts provided. This will not always be
|
||
what you want, for instance if running against an existing database that
|
||
already has test data in it. The likelihood of accidentally deleting
|
||
data is reduced by the commonest pattern (as shown above) that creates
|
||
the tables first and then inserts the data - the first step will fail if
|
||
the tables already exist.</para>
|
||
|
||
<para>However, to get more control over the creation and deletion of
|
||
existing data, the XML namespace provides a couple more options. The
|
||
first is flag to switch the initialization on and off. This can be set
|
||
according to the environment (e.g. to pull a boolean value from system
|
||
properties or an environment bean), e.g.
|
||
<programlisting><jdbc:initialize-database data-source="dataSource"
|
||
<emphasis role="bold">enabled="#{systemProperties.INITIALIZE_DATABASE}"</emphasis>>
|
||
<jdbc:script location="..."/>
|
||
</jdbc:initialize-database></programlisting></para>
|
||
|
||
<para>The second option to control what happens with existing data is to
|
||
be more tolerant of failures. To this end you can control the ability of
|
||
the initializer to ignore certain errors in the SQL it executes from the
|
||
scripts, e.g.</para>
|
||
|
||
<para><programlisting><jdbc:initialize-database data-source="dataSource" <emphasis
|
||
role="bold">ignore-failures="DROPS"</emphasis>>
|
||
<jdbc:script location="..."/>
|
||
</jdbc:initialize-database></programlisting>In this example we are
|
||
saying we expect that sometimes the scripts will be run against an empty
|
||
dtabase and there are some DROP statements in the scripts which would
|
||
therefore fail. So failed SQL <code>DROP</code> statements will be
|
||
ignored, but other failures will cause an exception. This is useful if
|
||
your SQL dialect doesn't support <code>DROP ... IF EXISTS</code> (or
|
||
similar) but you want to unconditionally remove all test data before
|
||
re-creating it. In that case the first script is usually a set of drops,
|
||
followed by a set of <code>CREATE</code> statements.</para>
|
||
|
||
<para>The <code>ignore-failures</code> option can be set to
|
||
<code>NONE</code> (the default), <code>DROPS</code> (ignore failed
|
||
drops) or <code>ALL</code> (ignore all failures).</para>
|
||
|
||
<para>If you need more control than you get from the XML namespace, you
|
||
can simply use the <classname>DataSourceInitializer</classname>
|
||
directly, and define it as a component in your application.</para>
|
||
|
||
<section>
|
||
<title>Initialization of Other Components that Depend on the
|
||
Database</title>
|
||
|
||
<para>A large class of applications can just use the database
|
||
initializer with no further complications: those that do not use the
|
||
database until after the Spring context has started. If your
|
||
application is <emphasis>not</emphasis> one of those then you might
|
||
need to read the rest of this section.</para>
|
||
|
||
<para>The database initializer depends on a data source instance and
|
||
runs the scripts provided in its initialization callback (c.f.
|
||
<code>init-method</code> in an XML bean definition or
|
||
<code>InitializingBean</code>). If other beans depend on the same data
|
||
source and also use the data source in an initialization callback then
|
||
there might be a problem because the data has not yet been
|
||
initialized. A common example of this is a cache that initializes
|
||
eagerly and loads up data from the database on application
|
||
startup.</para>
|
||
|
||
<para>To get round this issue you two options: change your cache
|
||
initialization strategy to a later phase, or ensure that the database
|
||
initializer is initialized first.</para>
|
||
|
||
<para>The first option might be easy if the application is in your
|
||
control, and not otherwise. Some suggestions for how to implement this
|
||
are<itemizedlist>
|
||
|
||
<listitem>
|
||
<para>Make the cache initialize lazily on first usage, which
|
||
improves application startup time</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Have your cache or a separate component that
|
||
initializes the cache implement <code>Lifecycle</code> or
|
||
<code>SmartLifecycle</code>. When the application context
|
||
starts up a <code>SmartLifecycle</code> can be automatically
|
||
started if its <code>autoStartup</code> flag is set,
|
||
and a <code>Lifecycle</code> can be started
|
||
manually by calling
|
||
<code>ConfigurableApplicationContext.start()</code> on the
|
||
enclosing context.
|
||
</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Use a Spring <code>ApplicationEvent</code> or similar
|
||
custom observer mechanism to trigger the cache initialization.
|
||
<code>ContextRefreshedEvent</code> is always published by the
|
||
context when it is ready for use (after all beans have been
|
||
initialized), so that is often a useful hook (this is
|
||
how the <code>SmartLifecycle</code> works by default).</para>
|
||
</listitem>
|
||
|
||
</itemizedlist></para>
|
||
|
||
<para>The second option can also be easy. Some suggestions on how to
|
||
implement this are<itemizedlist>
|
||
<listitem>
|
||
<para>Rely on Spring BeanFactory default behaviour, which is
|
||
that beans are initialized in registration order. You can easily
|
||
arrange that by adopting the common practice of a set of
|
||
<import/> elements that order your application modules,
|
||
and ensure that the database and database initialization are
|
||
listed first</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Separate the datasource and the business components that
|
||
use it and control their startup order by putting them in
|
||
separate ApplicationContext instances (e.g. parent has the
|
||
datasource and child has the business components). This
|
||
structure is common in Spring web applications, but can be more
|
||
generally applied.</para>
|
||
</listitem>
|
||
|
||
<listitem>
|
||
<para>Use a modular runtime like SpringSource dm Server and
|
||
separate the data source and the components that depend on it.
|
||
E.g. specify the bundle start up order as datasource ->
|
||
initializer -> business components.</para>
|
||
</listitem>
|
||
</itemizedlist></para>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
</chapter>
|