You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3038 lines
146 KiB
3038 lines
146 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.4/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 setter method for the |
|
<classname>DataSource</classname> with the |
|
<interfacename>@Autowired</interfacename> annotation.<!--Re preceding sentence, I don't see @Autowired in next two examples. TR: OK AS IS. Made it *bold*--></para> |
|
|
|
<para><programlisting language="java">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 a 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 StoredProcdedure class, you don't |
|
have to create a subclass and you don't have to declare parameters that |
|
can be looked up in the database metadata. <!--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 instead had a query the returned a list |
|
of objects and took additional parameters then we would use one of the |
|
execute methods that takes an array of parameter values passed in as |
|
varargs.</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><!--a LobCreator *what*? Say what it is. TR: Revised.-->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>setBlobAsBinartStream</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>JdbcTempate</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-datasource</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 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>
|
|
|