updating code examples with generics/varargs; polishing

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1136 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Thomas Risberg 2009-05-09 02:40:54 +00:00
parent 01e336dd5b
commit 79aae9dde9
2 changed files with 153 additions and 151 deletions

View File

@ -8,11 +8,11 @@
<title>Introduction</title> <title>Introduction</title>
<para>The Data Access Object (DAO) support in Spring is aimed at making it <para>The Data Access Object (DAO) support in Spring is aimed at making it
easy to work with data access technologies like JDBC, Hibernate or JDO in easy to work with data access technologies like JDBC, Hibernate, JPA or
a consistent way. This allows one to switch between the aforementioned JDO in a consistent way. This allows one to switch between the
persistence technologies fairly easily and it also allows one to code aforementioned persistence technologies fairly easily and it also allows
without worrying about catching exceptions that are specific to each one to code without worrying about catching exceptions that are specific
technology.</para> to each technology.</para>
</section> </section>
<section id="dao-exceptions"> <section id="dao-exceptions">

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<chapter id="jdbc"> <chapter id="jdbc">
<title>Data access using JDBC</title> <title>Data access using JDBC</title>
@ -73,8 +72,8 @@
<para><emphasis role="bold">JdbcTemplate</emphasis> - this is the <para><emphasis role="bold">JdbcTemplate</emphasis> - this is the
classic Spring JDBC approach and the most widely used. This is the classic Spring JDBC approach and the most widely used. This is the
"lowest level" approach and all other approaches use a JdbcTemplate "lowest level" approach and all other approaches use a JdbcTemplate
under the covers. Works well in a JDK 1.4 and higher under the covers. In Spring 3.0 it has been updated with Java 5
environment.</para> support like generics and vararg support. </para>
</listitem> </listitem>
<listitem> <listitem>
@ -82,16 +81,17 @@
wraps a JdbcTemplate to provide more convenient usage with named wraps a JdbcTemplate to provide more convenient usage with named
parameters instead of the traditional JDBC "?" place holders. This parameters instead of the traditional JDBC "?" place holders. This
provides better documentation and ease of use when you have multiple provides better documentation and ease of use when you have multiple
parameters for an SQL statement. Works with JDK 1.4 and up.</para> parameters for an SQL statement. It has also been updated with Java
5 support like generics and vararg support for Spring 3.0.</para>
</listitem> </listitem>
<listitem> <listitem>
<para><emphasis role="bold">SimpleJdbcTemplate</emphasis> - this <para><emphasis role="bold">SimpleJdbcTemplate</emphasis> - this
class combines the most frequently used features of both class combines the most frequently used features of both
JdbcTemplate and NamedParameterJdbcTemplate plus it adds additional JdbcTemplate and NamedParameterJdbcTemplate plus it adds additional
convenience by taking advantage of some Java 5 features like convenience by taking better advantage of Java 5 varargs for
varargs, autoboxing and generics to provide an easier to use API. ceratain methods where this wasn't possible in the JdbcTemplate due
Requires JDK 5 or higher.</para> to backwars compatibility reasons.</para>
</listitem> </listitem>
<listitem> <listitem>
@ -101,8 +101,8 @@
simplify the coding to a point where you only need to provide the simplify the coding to a point where you only need to provide the
name of the table or procedure and provide a Map of parameters name of the table or procedure and provide a Map of parameters
matching the column names. Designed to work together with the matching the column names. Designed to work together with the
SimpleJdbcTemplate. Requires JDK 5 or higher and a database that SimpleJdbcTemplate. Requires a database that provides adequate
provides adequate metadata.</para> metadata.</para>
</listitem> </listitem>
<listitem> <listitem>
@ -112,8 +112,9 @@
your data access layer. This approach is modeled after JDO Query your data access layer. This approach is modeled after JDO Query
where you define your query string, declare parameters and compile where you define your query string, declare parameters and compile
the query. Once that is done any execute methods can be called the query. Once that is done any execute methods can be called
multiple times with various parameter values passed in. Works with multiple times with various parameter values passed in. It has also
JDK 1.4 and higher.</para> been updated with Java 5 support like generics and vararg support
for Spring 3.0.</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</section> </section>
@ -231,48 +232,48 @@
<para>A simple query for getting the number of rows in a <para>A simple query for getting the number of rows in a
relation.</para> relation.</para>
<programlisting language="java">int rowCount = this.jdbcTemplate.queryForInt("select count(0) from t_accrual");</programlisting> <programlisting language="java"><![CDATA[int rowCount = this.jdbcTemplate.queryForInt("select count(*) from t_actor");]]></programlisting>
<para>A simple query using a bind variable.</para> <para>A simple query using a bind variable.</para>
<programlisting language="java">int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt( <programlisting language="java"><![CDATA[int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt(
"select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});</programlisting> "select count(*) from t_actor where first_name = ?", "Joe");]]></programlisting>
<para>Querying for a <classname>String</classname>.</para> <para>Querying for a <classname>String</classname>.</para>
<programlisting language="java">String surname = (String) this.jdbcTemplate.queryForObject( <programlisting language="java"><![CDATA[String surname = this.jdbcTemplate.queryForObject(
"select surname from t_actor where id = ?", "select surname from t_actor where id = ?",
new Object[]{new Long(1212)}, String.class);</programlisting> new Object[]{1212L}, String.class);]]></programlisting>
<para>Querying and populating a <emphasis>single</emphasis> domain <para>Querying and populating a <emphasis>single</emphasis> domain
object.</para> object.</para>
<programlisting language="java">Actor actor = (Actor) this.jdbcTemplate.queryForObject( <programlisting language="java"><![CDATA[Actor actor = this.jdbcTemplate.queryForObject(
"select first_name, surname from t_actor where id = ?", "select first_name, surname from t_actor where id = ?",
new Object[]{new Long(1212)}, new Object[]{1212L},
new RowMapper() { new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor();
Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name"));
actor.setFirstName(rs.getString("first_name")); actor.setSurname(rs.getString("surname"));
actor.setSurname(rs.getString("surname")); return actor;
return actor; }
} });
});</programlisting> ]]></programlisting>
<para>Querying and populating a number of domain objects.</para> <para>Querying and populating a number of domain objects.</para>
<programlisting language="java">Collection actors = this.jdbcTemplate.query( <programlisting language="java"><![CDATA[List<Actor> actors = this.jdbcTemplate.query(
"select first_name, surname from t_actor", "select first_name, surname from t_actor",
new RowMapper() { new RowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor();
Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name"));
actor.setFirstName(rs.getString("first_name")); actor.setSurname(rs.getString("surname"));
actor.setSurname(rs.getString("surname")); return actor;
return actor; }
} });
});</programlisting> ]]></programlisting>
<para>If the last two snippets of code actually existed in the same <para>If the last two snippets of code actually existed in the same
application, it would make sense to remove the duplication present application, it would make sense to remove the duplication present
@ -282,35 +283,35 @@
by DAO methods as needed. For example, the last code snippet might by DAO methods as needed. For example, the last code snippet might
be better off written like so:</para> be better off written like so:</para>
<programlisting language="java">public Collection findAllActors() { <programlisting language="java"><![CDATA[public List<Actor> findAllActors() {
return this.jdbcTemplate.query( "select first_name, surname from t_actor", new ActorMapper()); return this.jdbcTemplate.query( "select first_name, surname from t_actor", new ActorMapper());
} }
private static final class ActorMapper implements RowMapper { private static final class ActorMapper implements RowMapper<Actor> {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor(); Actor actor = new Actor();
actor.setFirstName(rs.getString("first_name")); actor.setFirstName(rs.getString("first_name"));
actor.setSurname(rs.getString("surname")); actor.setSurname(rs.getString("surname"));
return actor; return actor;
} }
}</programlisting> }]]></programlisting>
</section> </section>
<section id="jdbc-JdbcTemplate-examples-update"> <section id="jdbc-JdbcTemplate-examples-update">
<title>Updating (INSERT/UPDATE/DELETE)</title> <title>Updating (INSERT/UPDATE/DELETE)</title>
<programlisting language="java">this.jdbcTemplate.update( <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
"insert into t_actor (first_name, surname) values (?, ?)", "insert into t_actor (first_name, surname) values (?, ?)",
new Object[] {"Leonor", "Watling"});</programlisting> new Object[] {"Leonor", "Watling"});]]></programlisting>
<programlisting language="java">this.jdbcTemplate.update( <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
"update t_actor set weapon = ? where id = ?", "update t_actor set weapon = ? where id = ?",
new Object[] {"Banjo", new Long(5276)});</programlisting> new Object[] {"Banjo", new Long(5276)});]]></programlisting>
<programlisting language="java">this.jdbcTemplate.update( <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
"delete from actor where id = ?", "delete from actor where id = ?",
new Object[] {new Long.valueOf(actorId)});</programlisting> new Object[] {new Long.valueOf(actorId)});]]></programlisting>
</section> </section>
<section id="jdbc-JdbcTemplate-examples-other"> <section id="jdbc-JdbcTemplate-examples-other">
@ -321,15 +322,15 @@ private static final class ActorMapper implements RowMapper {
statements. It is heavily overloaded with variants taking callback statements. It is heavily overloaded with variants taking callback
interfaces, binding variable arrays, and suchlike.</para> interfaces, binding variable arrays, and suchlike.</para>
<programlisting language="java">this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");</programlisting> <programlisting language="java"><![CDATA[this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");]]></programlisting>
<para>Invoking a simple stored procedure (more sophisticated stored <para>Invoking a simple stored procedure (more sophisticated stored
procedure support is <link linkend="jdbc-StoredProcedure">covered procedure support is <link linkend="jdbc-StoredProcedure">covered
later</link>).</para> later</link>).</para>
<programlisting language="java">this.jdbcTemplate.update( <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
new Object[]{Long.valueOf(unionId)});</programlisting> new Object[]{Long.valueOf(unionId)});]]></programlisting>
</section> </section>
</section> </section>
@ -693,11 +694,11 @@ public Actor findActor(long id) {
used to connect to the database. Here is an example of how to configure used to connect to the database. Here is an example of how to configure
a <classname>DriverManagerDataSource</classname>:</para> a <classname>DriverManagerDataSource</classname>:</para>
<programlisting language="java">DriverManagerDataSource dataSource = new DriverManagerDataSource(); <programlisting language="java"><![CDATA[DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver"); dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:"); dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa"); dataSource.setUsername("sa");
dataSource.setPassword("");</programlisting> dataSource.setPassword("");]]></programlisting>
</section> </section>
<section id="jdbc-SQLExceptionTranslator"> <section id="jdbc-SQLExceptionTranslator">
@ -752,7 +753,7 @@ dataSource.setPassword("");</programlisting>
<para><classname>SQLErrorCodeSQLExceptionTranslator</classname> can be <para><classname>SQLErrorCodeSQLExceptionTranslator</classname> can be
extended the following way:</para> extended the following way:</para>
<programlisting language="java">public class MySQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator { <programlisting language="java"><![CDATA[public class MySQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) { protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
if (sqlex.getErrorCode() == -12345) { if (sqlex.getErrorCode() == -12345) {
@ -760,7 +761,7 @@ dataSource.setPassword("");</programlisting>
} }
return null; return null;
} }
}</programlisting> }]]></programlisting>
<para>In this example the specific error code <para>In this example the specific error code
<literal>'-12345'</literal> is translated and any other errors are <literal>'-12345'</literal> is translated and any other errors are
@ -802,7 +803,7 @@ su.update();</programlisting>
what you need to include for a minimal but fully functional class that what you need to include for a minimal but fully functional class that
creates a new table.</para> creates a new table.</para>
<programlisting language="java">import javax.sql.DataSource; <programlisting language="java"><![CDATA[import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAStatement { public class ExecuteAStatement {
@ -816,7 +817,7 @@ public class ExecuteAStatement {
public void doExecute() { public void doExecute() {
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))"); this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
} }
}</programlisting> }]]></programlisting>
</section> </section>
<section id="jdbc-statements-querying"> <section id="jdbc-statements-querying">
@ -836,7 +837,7 @@ public class ExecuteAStatement {
an <classname>int</classname> and one that queries for a an <classname>int</classname> and one that queries for a
<classname>String</classname>.</para> <classname>String</classname>.</para>
<programlisting language="java">import javax.sql.DataSource; <programlisting language="java"><![CDATA[import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
public class RunAQuery { public class RunAQuery {
@ -858,7 +859,7 @@ public class RunAQuery {
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource; this.dataSource = dataSource;
} }
}</programlisting> }]]></programlisting>
<para>In addition to the single results query methods there are several <para>In addition to the single results query methods there are several
methods that return a List with an entry for each row that the query methods that return a List with an entry for each row that the query
@ -870,7 +871,7 @@ public class RunAQuery {
above example to retrieve a list of all the rows, it would look like above example to retrieve a list of all the rows, it would look like
this:</para> this:</para>
<programlisting language="java"> <programlisting language="java"><![CDATA[
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
@ -879,11 +880,11 @@ public void setDataSource(DataSource dataSource) {
public List getList() { public List getList() {
return this.jdbcTemplate.queryForList("select * from mytable"); return this.jdbcTemplate.queryForList("select * from mytable");
}</programlisting> }]]></programlisting>
<para>The list returned would look something like this:</para> <para>The list returned would look something like this:</para>
<programlisting>[{name=Bob, id=1}, {name=Mary, id=2}]</programlisting> <programlisting><![CDATA[[{name=Bob, id=1}, {name=Mary, id=2}]]]></programlisting>
</section> </section>
<section id="jdbc-updates"> <section id="jdbc-updates">
@ -896,7 +897,7 @@ public List getList() {
objects (and thus primitives have to be wrapped in the primitive wrapper objects (and thus primitives have to be wrapped in the primitive wrapper
classes).</para> classes).</para>
<programlisting language="java">import javax.sql.DataSource; <programlisting language="java"><![CDATA[import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
@ -913,7 +914,7 @@ public class ExecuteAnUpdate {
"update mytable set name = ? where id = ?", "update mytable set name = ? where id = ?",
new Object[] {name, new Integer(id)}); new Object[] {name, new Integer(id)});
} }
}</programlisting> }]]></programlisting>
</section> </section>
<section id="jdbc-auto-genereted-keys"> <section id="jdbc-auto-genereted-keys">
@ -1016,8 +1017,9 @@ jdbcTemplate.update(
<para>The <classname>DriverManagerDataSource</classname> class is an <para>The <classname>DriverManagerDataSource</classname> class is an
implementation of the standard <interfacename>DataSource</interfacename> implementation of the standard <interfacename>DataSource</interfacename>
interface that configures a plain old JDBC Driver via bean properties, and interface that configures a plain old JDBC Driver via bean properties,
returns a new <interfacename>Connection</interfacename> every time.</para> and returns a new <interfacename>Connection</interfacename> every
time.</para>
<para>This is potentially useful for test or standalone environments <para>This is potentially useful for test or standalone environments
outside of a J2EE container, either as a outside of a J2EE container, either as a
@ -1172,7 +1174,7 @@ jdbcTemplate.update(
where we update the actor table based on entries in a list. The entire where we update the actor table based on entries in a list. The entire
list is used as the batch in his example.</para> list is used as the batch in his example.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
@ -1197,7 +1199,7 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>If you are processing stream of updates or reading from a }]]></programlisting>If you are processing stream of updates or reading from a
file then you might have a preferred batch size, but the last batch 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 might not have that number of entries. In this case you can use the
<classname>InterruptibleBatchPreparedStatementSetter</classname> <classname>InterruptibleBatchPreparedStatementSetter</classname>
@ -1223,14 +1225,14 @@ jdbcTemplate.update(
<para>This example shows a batch update using named parameters:</para> <para>This example shows a batch update using named parameters:</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
} }
public int[] batchUpdate(final List&lt;Actor&gt; actors) { public int[] batchUpdate(final List<Actor> actors) {
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray()); SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());
int[] updateCounts = simpleJdbcTemplate.batchUpdate( int[] updateCounts = simpleJdbcTemplate.batchUpdate(
"update t_actor set first_name = :firstName, last_name = :lastName where id = :id", "update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
@ -1239,23 +1241,23 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>For an SQL statement using the classic "?" place holders you }]]></programlisting>For an SQL statement using the classic "?" place holders
pass in a List containing an object array with the update values. This you pass in a List containing an object array with the update values.
object array must have one entry for each placeholder in the SQL 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 statement and they must be in the same order as they are defined in the
SQL statement.</para> SQL statement.</para>
<para>The same example using classic JDBC "?" place holders:</para> <para>The same example using classic JDBC "?" place holders:</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
} }
public int[] batchUpdate(final List&lt;Actor&gt; actors) { public int[] batchUpdate(final List<Actor> actors) {
List&lt;Object[]&gt; batch = new ArrayList&lt;Object[]&gt;(); List<Object[]> batch = new ArrayList<Object[]>();
for (Actor actor : actors) { for (Actor actor : actors) {
Object[] values = new Object[] { Object[] values = new Object[] {
actor.getFirstName(), actor.getFirstName(),
@ -1270,9 +1272,9 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>All batch update methods return an int array containing the }]]></programlisting>All batch update methods return an int array containing
number of affected rows for each batch entry. This count is reported by the number of affected rows for each batch entry. This count is reported
the JDBC driver and it's not always available in which case the JDBC by the JDBC driver and it's not always available in which case the JDBC
driver simply returns a -2 value.</para> driver simply returns a -2 value.</para>
</section> </section>
</section> </section>
@ -1304,7 +1306,7 @@ jdbcTemplate.update(
configuration methods. In this case there is only one configuration configuration methods. In this case there is only one configuration
method used but we will see examples of multiple ones soon.</para> method used but we will see examples of multiple ones soon.</para>
<programlisting language="java">public class JdbcActorDao implements ActorDao { <programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor; private SimpleJdbcInsert insertActor;
@ -1315,7 +1317,7 @@ jdbcTemplate.update(
} }
public void add(Actor actor) { public void add(Actor actor) {
Map&lt;String, Object&gt; parameters = new HashMap&lt;String, Object&gt;(3); Map<String, Object> parameters = new HashMap<String, Object>(3);
parameters.put("id", actor.getId()); parameters.put("id", actor.getId());
parameters.put("first_name", actor.getFirstName()); parameters.put("first_name", actor.getFirstName());
parameters.put("last_name", actor.getLastName()); parameters.put("last_name", actor.getLastName());
@ -1323,7 +1325,7 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting> }]]></programlisting>
<para>The execute method used here takes a plain <para>The execute method used here takes a plain
<classname>java.utils.Map</classname> as its only parameter. The <classname>java.utils.Map</classname> as its only parameter. The
@ -1343,7 +1345,7 @@ jdbcTemplate.update(
generated key column using the generated key column using the
<classname>usingGeneratedKeyColumns</classname> method.</para> <classname>usingGeneratedKeyColumns</classname> method.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor; private SimpleJdbcInsert insertActor;
@ -1356,7 +1358,7 @@ jdbcTemplate.update(
} }
public void add(Actor actor) { public void add(Actor actor) {
Map&lt;String, Object&gt; parameters = new HashMap&lt;String, Object&gt;(2); Map<String, Object> parameters = new HashMap<String, Object>(2);
parameters.put("first_name", actor.getFirstName()); parameters.put("first_name", actor.getFirstName());
parameters.put("last_name", actor.getLastName()); parameters.put("last_name", actor.getLastName());
Number newId = insertActor.executeAndReturnKey(parameters); Number newId = insertActor.executeAndReturnKey(parameters);
@ -1364,7 +1366,7 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>Here we can see the main difference when executing the }]]></programlisting>Here we can see the main difference when executing the
insert is that we don't add the id to the Map and we call the insert is that we don't add the id to the Map and we call the
<literal>executeReturningKey</literal> method. This returns a <literal>executeReturningKey</literal> method. This returns a
<literal>java.lang.Number</literal> object that we can use to create an <literal>java.lang.Number</literal> object that we can use to create an
@ -1384,7 +1386,7 @@ jdbcTemplate.update(
specifying a list of column names to be used. This is accomplished using specifying a list of column names to be used. This is accomplished using
the <classname>usingColumns</classname> method.</para> the <classname>usingColumns</classname> method.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor; private SimpleJdbcInsert insertActor;
@ -1398,7 +1400,7 @@ jdbcTemplate.update(
} }
public void add(Actor actor) { public void add(Actor actor) {
Map&lt;String, Object&gt; parameters = new HashMap&lt;String, Object&gt;(2); Map<String, Object> parameters = new HashMap<String, Object>(2);
parameters.put("first_name", actor.getFirstName()); parameters.put("first_name", actor.getFirstName());
parameters.put("last_name", actor.getLastName()); parameters.put("last_name", actor.getLastName());
Number newId = insertActor.executeAndReturnKey(parameters); Number newId = insertActor.executeAndReturnKey(parameters);
@ -1406,8 +1408,8 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>The execution of the insert is the same as if we had relied }]]></programlisting>The execution of the insert is the same as if we had
on the metadata for determining what columns to use.</para> relied on the metadata for determining what columns to use.</para>
</section> </section>
<section id="jdbc-simple-jdbc-parameters"> <section id="jdbc-simple-jdbc-parameters">
@ -1422,7 +1424,7 @@ jdbcTemplate.update(
contains your values. It will use the corresponding getter method to contains your values. It will use the corresponding getter method to
extract the parameter values. Here is an example:</para> extract the parameter values. Here is an example:</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor; private SimpleJdbcInsert insertActor;
@ -1441,12 +1443,12 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>Another option is the }]]></programlisting>Another option is the
<classname>MapSqlParameterSource</classname> that resembles a Map but <classname>MapSqlParameterSource</classname> that resembles a Map but
provides a more convenient <classname>addValue</classname> method that provides a more convenient <classname>addValue</classname> method that
can be chained.</para> can be chained.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor; private SimpleJdbcInsert insertActor;
@ -1467,8 +1469,8 @@ jdbcTemplate.update(
} }
// ... additional methods // ... additional methods
}</programlisting>As you can see, the configuration is the same, it;s just the }]]></programlisting>As you can see, the configuration is the same, it;s just
executing code that has to change to use these alternative input the executing code that has to change to use these alternative input
classes.</para> classes.</para>
</section> </section>
@ -1491,7 +1493,7 @@ jdbcTemplate.update(
the source for the procedure as it would look when using MySQL as the the source for the procedure as it would look when using MySQL as the
database:</para> database:</para>
<para><programlisting>CREATE PROCEDURE read_actor ( <para><programlisting><![CDATA[CREATE PROCEDURE read_actor (
IN in_id INTEGER, IN in_id INTEGER,
OUT out_first_name VARCHAR(100), OUT out_first_name VARCHAR(100),
OUT out_last_name VARCHAR(100), OUT out_last_name VARCHAR(100),
@ -1500,7 +1502,7 @@ BEGIN
SELECT first_name, last_name, birth_date SELECT first_name, last_name, birth_date
INTO out_first_name, out_last_name, out_birth_date INTO out_first_name, out_last_name, out_birth_date
FROM t_actor where id = in_id; FROM t_actor where id = in_id;
END;</programlisting>As you can see there are four parameters. One is an in END;]]></programlisting>As you can see there are four parameters. One is an in
parameter "in_id" containing the id of the Actor we are looking up. The parameter "in_id" containing the id of the Actor we are looking up. The
remaining parameters are out parameters and they will be used to return remaining parameters are out parameters and they will be used to return
the data read from the table.</para> the data read from the table.</para>
@ -1510,7 +1512,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
subclass and we declare it in the initialization method. For this subclass and we declare it in the initialization method. For this
example, all we need to specify is the name of the procedure.</para> example, all we need to specify is the name of the procedure.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcCall procReadActor; private SimpleJdbcCall procReadActor;
@ -1534,7 +1536,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
} }
// ... additional methods // ... additional methods
}</programlisting>The execution of the call involves creating an }]]></programlisting>The execution of the call involves creating an
<classname>SqlParameterSource</classname> containing the in parameter. <classname>SqlParameterSource</classname> containing the in parameter.
It's important to match the name of the parameter declared in the stored It's important to match the name of the parameter declared in the stored
procedure. The case doesn't have to match since we use metadata to procedure. The case doesn't have to match since we use metadata to
@ -1565,7 +1567,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
<classname>commons-collections.jar</classname> on your classpath for <classname>commons-collections.jar</classname> on your classpath for
this to work. Here is an example of this configuration:</para> this to work. Here is an example of this configuration:</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcCall procReadActor; private SimpleJdbcCall procReadActor;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
@ -1578,8 +1580,8 @@ END;</programlisting>As you can see there are four parameters. One is an in
// ... additional methods // ... additional methods
}</programlisting>By doing this, you don't have to worry about the case used }]]></programlisting>By doing this, you don't have to worry about the case
for the names of your returned out parameters.</para> used for the names of your returned out parameters.</para>
</section> </section>
<section id="jdbc-simple-jdbc-call-2"> <section id="jdbc-simple-jdbc-call-2">
@ -1606,7 +1608,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
<para>This is what a fully declared procedure call declaration of our <para>This is what a fully declared procedure call declaration of our
earlier example would look like:</para> earlier example would look like:</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcCall procReadActor; private SimpleJdbcCall procReadActor;
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
@ -1627,7 +1629,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
// ... additional methods // ... additional methods
}</programlisting>The execution and end results are the same, we are just }]]></programlisting>The execution and end results are the same, we are just
specifying all the details explicitly rather than relying on metadata. specifying all the details explicitly rather than relying on metadata.
This will be necessary if the database we use is not part of the This will be necessary if the database we use is not part of the
supported databases. Currently we support metadata lookup of stored supported databases. Currently we support metadata lookup of stored
@ -1647,8 +1649,8 @@ END;</programlisting>As you can see there are four parameters. One is an in
<classname>java.sql.Types</classname> constants. We have already seen <classname>java.sql.Types</classname> constants. We have already seen
declarations like:</para> declarations like:</para>
<para><programlisting language="java"> new SqlParameter("in_id", Types.NUMERIC), <para><programlisting language="java"><![CDATA[ new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),</programlisting></para> new SqlOutParameter("out_first_name", Types.VARCHAR),]]></programlisting></para>
<para>The first line with the <classname>SqlParameter</classname> <para>The first line with the <classname>SqlParameter</classname>
declares an in parameter. In parameters can be used for both stored declares an in parameter. In parameters can be used for both stored
@ -1668,7 +1670,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
input values. This is different from the input values. This is different from the
<classname>StoredProcedure</classname> class which for backwards <classname>StoredProcedure</classname> class which for backwards
compatibility reasons allows input values to be provided for compatibility reasons allows input values to be provided for
parameters declared as <classname>SqlOutParameter</classname>. </para> parameters declared as <classname>SqlOutParameter</classname>.</para>
</note> </note>
<para>In addition to the name and the SQL type you can specify <para>In addition to the name and the SQL type you can specify
@ -1699,7 +1701,7 @@ END;</programlisting>As you can see there are four parameters. One is an in
that returns an actor's full name. Here is the MySQL source for this that returns an actor's full name. Here is the MySQL source for this
function:</para> function:</para>
<para><programlisting>CREATE FUNCTION get_actor_name (in_id INTEGER) <para><programlisting><![CDATA[CREATE FUNCTION get_actor_name (in_id INTEGER)
RETURNS VARCHAR(200) READS SQL DATA RETURNS VARCHAR(200) READS SQL DATA
BEGIN BEGIN
DECLARE out_name VARCHAR(200); DECLARE out_name VARCHAR(200);
@ -1707,13 +1709,13 @@ BEGIN
INTO out_name INTO out_name
FROM t_actor where id = in_id; FROM t_actor where id = in_id;
RETURN out_name; RETURN out_name;
END;</programlisting></para> END;]]></programlisting></para>
<para>To call this function we again create a <para>To call this function we again create a
<classname>SimpleJdbcCall</classname> in the initialization <classname>SimpleJdbcCall</classname> in the initialization
method.</para> method.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcCall funcGetActorName; private SimpleJdbcCall funcGetActorName;
@ -1734,7 +1736,7 @@ END;</programlisting></para>
} }
// ... additional methods // ... additional methods
}</programlisting>The execute method used returns a }]]></programlisting>The execute method used returns a
<classname>String</classname> containing the return value from the <classname>String</classname> containing the return value from the
function call.</para> function call.</para>
</section> </section>
@ -1761,17 +1763,17 @@ END;</programlisting></para>
parameters and returns all rows from the t_actor table. Here is the parameters and returns all rows from the t_actor table. Here is the
MySQL source for this procedure:</para> MySQL source for this procedure:</para>
<para><programlisting>CREATE PROCEDURE read_all_actors() <para><programlisting><![CDATA[CREATE PROCEDURE read_all_actors()
BEGIN BEGIN
SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a; SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a;
END;</programlisting>In order to call this procedure we need to declare the END;]]></programlisting>In order to call this procedure we need to declare the
<classname>RowMapper</classname> to be used. Since the class we want to <classname>RowMapper</classname> to be used. Since the class we want to
map to follows the JavaBean rules, we can use a map to follows the JavaBean rules, we can use a
<classname>ParameterizedBeanPropertyRowMapper</classname> that is <classname>ParameterizedBeanPropertyRowMapper</classname> that is
created by passing in the required class to map to in the created by passing in the required class to map to in the
<classname>newInstance</classname> method.</para> <classname>newInstance</classname> method.</para>
<para><programlisting language="java">public class JdbcActorDao implements ActorDao { <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcCall procReadAllActors; private SimpleJdbcCall procReadAllActors;
@ -1787,12 +1789,12 @@ END;</programlisting>In order to call this procedure we need to declare the
} }
public List getActorsList() { public List getActorsList() {
Map m = procReadAllActors.execute(new HashMap&lt;String, Object&gt;(0)); Map m = procReadAllActors.execute(new HashMap<String, Object>(0));
return (List) m.get("actors"); return (List) m.get("actors");
} }
// ... additional methods // ... additional methods
}</programlisting>The execute call passes in an empty Map since this call }]]></programlisting>The execute call passes in an empty Map since this call
doesn't take any parameters. The list of Actors is then retrieved from doesn't take any parameters. The list of Actors is then retrieved from
the results map and returned to the caller.</para> the results map and returned to the caller.</para>
</section> </section>
@ -1855,7 +1857,7 @@ END;</programlisting>In order to call this procedure we need to declare the
customer relation to an instance of the <classname>Customer</classname> customer relation to an instance of the <classname>Customer</classname>
class.</para> class.</para>
<programlisting language="java">private class CustomerMappingQuery extends MappingSqlQuery { <programlisting language="java"><![CDATA[private class CustomerMappingQuery extends MappingSqlQuery {
public CustomerMappingQuery(DataSource ds) { public CustomerMappingQuery(DataSource ds) {
super(ds, "SELECT id, name FROM customer WHERE id = ?"); super(ds, "SELECT id, name FROM customer WHERE id = ?");
@ -1869,7 +1871,7 @@ END;</programlisting>In order to call this procedure we need to declare the
cust.setName(rs.getString("name")); cust.setName(rs.getString("name"));
return cust; return cust;
} }
}</programlisting> }]]></programlisting>
<para>We provide a constructor for this customer query that takes the <para>We provide a constructor for this customer query that takes the
<interfacename>DataSource</interfacename> as the only parameter. In this <interfacename>DataSource</interfacename> as the only parameter. In this
@ -1886,18 +1888,18 @@ END;</programlisting>In order to call this procedure we need to declare the
have been defined we call the <literal>compile()</literal> method so the have been defined we call the <literal>compile()</literal> method so the
statement can be prepared and later be executed.</para> statement can be prepared and later be executed.</para>
<programlisting language="java">public Customer getCustomer(Integer id) { <programlisting language="java"><![CDATA[public Customer getCustomer(Integer id) {
CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource); CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource);
Object[] parms = new Object[1]; Object[] parms = new Object[1];
parms[0] = id; parms[0] = id;
List customers = custQry.execute(parms); List customers = custQry.execute(parms);
if (customers.size() &gt; 0) { if (customers.size() > 0) {
return (Customer) customers.get(0); return (Customer) customers.get(0);
} }
else { else {
return null; return null;
} }
}</programlisting> }]]></programlisting>
<para>The method in this example retrieves the customer with the id that <para>The method in this example retrieves the customer with the id that
is passed in as the only parameter. After creating an instance of the is passed in as the only parameter. After creating an instance of the
@ -1975,8 +1977,8 @@ public class UpdateCreditRating extends SqlUpdate {
SQL type is specified using the <classname>java.sql.Types</classname> SQL type is specified using the <classname>java.sql.Types</classname>
constants. We have already seen declarations like:</para> constants. We have already seen declarations like:</para>
<para><programlisting language="java"> new SqlParameter("in_id", Types.NUMERIC), <para><programlisting language="java"><![CDATA[ new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),</programlisting></para> new SqlOutParameter("out_first_name", Types.VARCHAR),]]></programlisting></para>
<para>The first line with the <classname>SqlParameter</classname> <para>The first line with the <classname>SqlParameter</classname>
declares an in parameter. In parameters can be used for both stored declares an in parameter. In parameters can be used for both stored
@ -1991,11 +1993,11 @@ public class UpdateCreditRating extends SqlUpdate {
that also return a value</para> that also return a value</para>
<para><note> <para><note>
<para> Parameters declared as <classname>SqlParameter</classname> <para>Parameters declared as <classname>SqlParameter</classname> and
and <classname>SqlInOutParameter</classname> will always be used to <classname>SqlInOutParameter</classname> will always be used to
provide input values. In addition to this any parameter declared as provide input values. In addition to this any parameter declared as
<classname>SqlOutParameter</classname> where an non-null input value <classname>SqlOutParameter</classname> where an non-null input value
is provided will also be used as an input paraneter. </para> is provided will also be used as an input paraneter.</para>
</note></para> </note></para>
<para>In addition to the name and the SQL type you can specify <para>In addition to the name and the SQL type you can specify
@ -2113,7 +2115,7 @@ public class TitlesAndGenresStoredProcedure extends StoredProcedure {
<classname>Title</classname> domain object for each row in the supplied <classname>Title</classname> domain object for each row in the supplied
<interfacename>ResultSet</interfacename>.</para> <interfacename>ResultSet</interfacename>.</para>
<programlisting language="java">import com.foo.sprocs.domain.Title; <programlisting language="java"><![CDATA[import com.foo.sprocs.domain.Title;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -2127,14 +2129,14 @@ public final class TitleMapper implements RowMapper {
title.setName(rs.getString("name")); title.setName(rs.getString("name"));
return title; return title;
} }
}</programlisting> }]]></programlisting>
<para>Secondly, the <classname>GenreMapper</classname> class, which <para>Secondly, the <classname>GenreMapper</classname> class, which
again simply maps a <interfacename>ResultSet</interfacename> to a again simply maps a <interfacename>ResultSet</interfacename> to a
<classname>Genre</classname> domain object for each row in the supplied <classname>Genre</classname> domain object for each row in the supplied
<interfacename>ResultSet</interfacename>.</para> <interfacename>ResultSet</interfacename>.</para>
<programlisting language="java">import org.springframework.jdbc.core.RowMapper; <programlisting language="java"><![CDATA[import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@ -2146,7 +2148,7 @@ public final class GenreMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException { public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Genre(rs.getString("name")); return new Genre(rs.getString("name"));
} }
}</programlisting> }]]></programlisting>
<para>If one needs to pass parameters to a stored procedure (that is the <para>If one needs to pass parameters to a stored procedure (that is the
stored procedure has been declared as having one or more input stored procedure has been declared as having one or more input
@ -2155,7 +2157,7 @@ public final class GenreMapper implements RowMapper {
superclass' (untyped) <literal>execute(Map parameters)</literal> (which superclass' (untyped) <literal>execute(Map parameters)</literal> (which
has <literal>protected</literal> access); for example:</para> has <literal>protected</literal> access); for example:</para>
<programlisting language="java">import oracle.jdbc.driver.OracleTypes; <programlisting language="java"><![CDATA[import oracle.jdbc.driver.OracleTypes;
import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.object.StoredProcedure; import org.springframework.jdbc.object.StoredProcedure;
@ -2180,7 +2182,7 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure {
inputs.put(CUTOFF_DATE_PARAM, cutoffDate); inputs.put(CUTOFF_DATE_PARAM, cutoffDate);
return super.execute(inputs); return super.execute(inputs);
} }
}</programlisting> }]]></programlisting>
</section> </section>
<section id="jdbc-SqlFunction"> <section id="jdbc-SqlFunction">
@ -2211,11 +2213,11 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure {
the appropriate run method repeatedly to execute the function. Here is the appropriate run method repeatedly to execute the function. Here is
an example of retrieving the count of rows from a table:</para> an example of retrieving the count of rows from a table:</para>
<programlisting language="java">public int countRows() { <programlisting language="java"><![CDATA[public int countRows() {
SqlFunction sf = new SqlFunction(dataSource, "select count(*) from mytable"); SqlFunction sf = new SqlFunction(dataSource, "select count(*) from mytable");
sf.compile(); sf.compile();
return sf.run(); return sf.run();
}</programlisting> }]]></programlisting>
</section> </section>
</section> </section>
@ -2346,7 +2348,7 @@ public class TitlesAfterDateStoredProcedure extends StoredProcedure {
<area coords="13" id="jdbc.lobhandler.setBlob" /> <area coords="13" id="jdbc.lobhandler.setBlob" />
</areaspec> </areaspec>
<programlisting language="java">final File blobIn = new File("spring2004.jpg"); <programlisting language="java"><![CDATA[final File blobIn = new File("spring2004.jpg");
final InputStream blobIs = new FileInputStream(blobIn); final InputStream blobIs = new FileInputStream(blobIn);
final File clobIn = new File("large.txt"); final File clobIn = new File("large.txt");
final InputStream clobIs = new FileInputStream(clobIn); final InputStream clobIs = new FileInputStream(clobIn);
@ -2363,7 +2365,7 @@ jdbcTemplate.execute(
} }
); );
blobIs.close(); blobIs.close();
clobReader.close();</programlisting> clobReader.close();]]></programlisting>
<calloutlist> <calloutlist>
<callout arearefs="jdbc.lobhandler.variableref"> <callout arearefs="jdbc.lobhandler.variableref">
@ -2395,7 +2397,7 @@ clobReader.close();</programlisting>
<area coords="7" id="jdbc.lobhandler.getBlob" /> <area coords="7" id="jdbc.lobhandler.getBlob" />
</areaspec> </areaspec>
<programlisting language="java">List l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table", <programlisting language="java"><![CDATA[List l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",
new RowMapper() { new RowMapper() {
public Object mapRow(ResultSet rs, int i) throws SQLException { public Object mapRow(ResultSet rs, int i) throws SQLException {
Map results = new HashMap(); Map results = new HashMap();
@ -2406,7 +2408,7 @@ clobReader.close();</programlisting>
return results; return results;
} }
}); });
</programlisting> ]]></programlisting>
<calloutlist> <calloutlist>
<callout arearefs="jdbc.lobhandler.setClob"> <callout arearefs="jdbc.lobhandler.setClob">
@ -2474,7 +2476,7 @@ clobReader.close();</programlisting>
interface is used as part of the declaration of an interface is used as part of the declaration of an
<classname>SqlOutParameter</classname>.</para> <classname>SqlOutParameter</classname>.</para>
<para><programlisting language="java">declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE", <para><programlisting language="java"><![CDATA[declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE",
new SqlReturnType() { new SqlReturnType() {
public Object getTypeValue(CallableStatement cs, int colIndx, int sqlType, String typeName) public Object getTypeValue(CallableStatement cs, int colIndx, int sqlType, String typeName)
throws SQLException { throws SQLException {
@ -2486,7 +2488,7 @@ clobReader.close();</programlisting>
item.setExpirationDate((java.util.Date)attr[2]); item.setExpirationDate((java.util.Date)attr[2]);
return item; return item;
} }
}));</programlisting>Going from Java to the database and passing in the }));]]></programlisting>Going from Java to the database and passing in the
value of a <classname>TestItem</classname> into a stored procedure is value of a <classname>TestItem</classname> into a stored procedure is
done using the <classname>SqlTypeValue</classname>. The done using the <classname>SqlTypeValue</classname>. The
<classname>SqlTypeValue</classname> interface has a single method named <classname>SqlTypeValue</classname> interface has a single method named
@ -2495,7 +2497,7 @@ clobReader.close();</programlisting>
specific objects like <classname>StructDescriptor</classname>s or specific objects like <classname>StructDescriptor</classname>s or
<classname>ArrayDescriptor</classname>s</para> <classname>ArrayDescriptor</classname>s</para>
<para><programlisting language="java">SqlTypeValue value = new AbstractSqlTypeValue() { <para><programlisting language="java"><![CDATA[SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException { protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn); StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn);
Struct item = new STRUCT(itemDescriptor, conn, Struct item = new STRUCT(itemDescriptor, conn,
@ -2506,9 +2508,9 @@ clobReader.close();</programlisting>
}); });
return item; return item;
} }
};</programlisting>This <classname>SqlTypeValue</classname> can now be added };]]></programlisting>This <classname>SqlTypeValue</classname> can now be
to the Map containing the input parameters for the execute call of the added to the Map containing the input parameters for the execute call of
stored procedure.</para> the stored procedure.</para>
</section> </section>
</section> </section>
</chapter> </chapter>