jdbc.xml 126.5 KB
Newer Older
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
<chapter id="jdbc">
  <title>Data access using JDBC</title>

  <section id="jdbc-introduction">
    <title>Introduction</title>

    <para>The value-add provided by the Spring Framework's JDBC abstraction
    framework is perhaps best shown by the following list (note that only the
    italicized lines need to be coded by an application developer):</para>

    <orderedlist numeration="arabic">
      <listitem>
        <para>Define connection parameters</para>
      </listitem>

      <listitem>
        <para>Open the connection</para>
      </listitem>

      <listitem>
        <para><emphasis>Specify the statement</emphasis></para>
      </listitem>

      <listitem>
        <para>Prepare and execute the statement</para>
      </listitem>

      <listitem>
        <para>Set up the loop to iterate through the results (if any)</para>
      </listitem>

      <listitem>
        <para><emphasis>Do the work for each iteration</emphasis></para>
      </listitem>

      <listitem>
        <para>Process any exception</para>
      </listitem>

      <listitem>
        <para>Handle transactions</para>
      </listitem>

      <listitem>
        <para>Close the connection</para>
      </listitem>
    </orderedlist>

    <para>The Spring Framework takes care of all the grungy, low-level details
    that can make JDBC such a tedious API to develop with.</para>

    <section id="jdbc-choose-style">
      <title>Choosing a style</title>

      <para>There are a number of options for selecting an approach to form
      the basis for your JDBC database access. There are three flavors of the
      JdbcTemplate, a new "SimpleJdbc" approach taking advantage of database
      metadata, and there is also the "RDBMS Object" style for a more object
      oriented approach similar in style to the JDO Query design. We'll
      briefly list the primary reasons why you would pick one of these
      approaches. Keep in mind that even if you start using one of these
      approaches, you can still mix and match if there is a feature in a
      different approach that you would like to take advantage of. All
      approaches requires a JDBC 2.0 compliant driver and some advanced
      features require a JDBC 3.0 driver.</para>

      <itemizedlist>
        <listitem>
          <para><emphasis role="bold">JdbcTemplate</emphasis> - 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
75
          under the covers. In Spring 3.0 it has been updated with Java 5
76
          support like generics and varargs.</para>
77 78 79 80 81 82 83
        </listitem>

        <listitem>
          <para><emphasis role="bold">NamedParameterJdbcTemplate</emphasis> -
          wraps a JdbcTemplate to provide more convenient usage with named
          parameters instead of the traditional JDBC "?" place holders. This
          provides better documentation and ease of use when you have multiple
84
          parameters for an SQL statement. It has also been updated with Java
85
          5 support like generics and varargs for Spring 3.0.</para>
86 87 88 89
        </listitem>

        <listitem>
          <para><emphasis role="bold">SimpleJdbcTemplate</emphasis> - this
K
Keith Donald 已提交
90
          class combines the most frequently used operations across
91 92 93 94
          JdbcTemplate and NamedParameterJdbcTemplate. It also adds some
          additional convenience around support for Java 5 varargs where this
          was not possible in the JdbcTemplate due to backwards compatibility
          reasons.</para>
95 96 97 98 99 100 101 102 103
        </listitem>

        <listitem>
          <para><emphasis role="bold">SimpleJdbcInsert and
          SimpleJdbcCall</emphasis> - designed to take advantage of database
          metadata to limit the amount of configuration needed. This will
          simplify the coding to a point where you only need to provide the
          name of the table or procedure and provide a Map of parameters
          matching the column names. Designed to work together with the
104 105
          SimpleJdbcTemplate. Requires a database that provides adequate
          metadata.</para>
106 107 108 109 110 111 112 113 114
        </listitem>

        <listitem>
          <para><emphasis role="bold">RDBMS Objects including MappingSqlQuery,
          SqlUpdate and StoredProcedure</emphasis> - an approach where you
          create reusable and thread safe objects during initialization of
          your data access layer. This approach is modeled after JDO Query
          where you define your query string, declare parameters and compile
          the query. Once that is done any execute methods can be called
115 116 117
          multiple times with various parameter values passed in. It has also
          been updated with Java 5 support like generics and vararg support
          for Spring 3.0.</para>
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        </listitem>
      </itemizedlist>
    </section>

    <section id="jdbc-packages">
      <title>The package hierarchy</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 sub-package
      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 sub-package named
      <literal>org.springframework.jdbc.core.namedparam</literal> contains the
      <classname>NamedParameterJdbcTemplate</classname> class and the related
      support classes.</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
145 146 147 148 149
      used for testing and running unmodified JDBC code outside of a Java EE
      container. A sub-package 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.</para>
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234

      <para>Next, the <literal>org.springframework.jdbc.object</literal>
      package contains classes that represent RDBMS queries, updates, and
      stored procedures as thread safe, reusable objects. This approach is
      modeled by JDO, although of course objects returned by queries are
      <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>Finally the <literal>org.springframework.jdbc.support</literal>
      package is where you find the <classname>SQLException</classname>
      translation functionality and some utility classes.</para>

      <para>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 giving you the option of catching
      the exceptions that you can recover from while allowing other exceptions
      to be propagated to the caller.</para>
    </section>
  </section>

  <section id="jdbc-core">
    <title>Using the JDBC Core classes to control basic JDBC processing and
    error handling</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 simplifies the use of JDBC since it handles
      the creation and release of resources. This helps to avoid common errors
      such as forgetting to always close the connection. It executes the core
      JDBC workflow like statement creation and execution, leaving application
      code to provide SQL and extract results. This class executes SQL
      queries, update statements or stored procedure calls, imitating
      iteration over <interfacename>ResultSet</interfacename>s and extraction
      of returned parameter values. 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>Code using the <classname>JdbcTemplate</classname> 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 statement. The
      <interfacename>RowCallbackHandler</interfacename> interface extracts
      values from each row of a
      <interfacename>ResultSet</interfacename>.</para>

      <para>The <classname>JdbcTemplate</classname> can be used within a DAO
      implementation via 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: the
      <interfacename>DataSource</interfacename> should always be configured as
      a bean in the Spring IoC container, in the first case given to the
      service directly, in the second case to the prepared template.</para>

      <para>Finally, all of the 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 a custom
      subclass of the <classname>JdbcTemplate</classname> class is being
      used).</para>

      <section id="jdbc-JdbcTemplate-examples">
        <title>Examples</title>

        <para>Find below some examples of using the
        <classname>JdbcTemplate</classname> class. (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>A simple query for getting the number of rows in a
          relation.</para>

235
          <programlisting language="java"><![CDATA[int rowCount = this.jdbcTemplate.queryForInt("select count(*) from t_actor");]]></programlisting>
236 237 238

          <para>A simple query using a bind variable.</para>

239 240
          <programlisting language="java"><![CDATA[int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt(
        "select count(*) from t_actor where first_name = ?", "Joe");]]></programlisting>
241 242 243

          <para>Querying for a <classname>String</classname>.</para>

244 245
          <programlisting language="java"><![CDATA[String lastName = this.jdbcTemplate.queryForObject(
        "select last_name from t_actor where id = ?", 
246
        new Object[]{1212L}, String.class);]]></programlisting>
247 248 249 250

          <para>Querying and populating a <emphasis>single</emphasis> domain
          object.</para>

251
          <programlisting language="java"><![CDATA[Actor actor = this.jdbcTemplate.queryForObject(
252
        "select first_name, last_name from t_actor where id = ?",
253 254 255 256 257
        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"));
258
                actor.setLastName(rs.getString("last_name"));
259 260 261 262
                return actor;
            }
        });
]]></programlisting>
263 264 265

          <para>Querying and populating a number of domain objects.</para>

266
          <programlisting language="java"><![CDATA[List<Actor> actors = this.jdbcTemplate.query(
267
        "select first_name, last_name from t_actor",
268 269 270 271
        new RowMapper<Actor>() {
            public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
                Actor actor = new Actor();
                actor.setFirstName(rs.getString("first_name"));
272
                actor.setLastName(rs.getString("last_name"));
273 274 275 276
                return actor;
            }
        });
]]></programlisting>
277 278 279 280 281 282 283 284 285

          <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, the last code snippet might
          be better off written like so:</para>

286
          <programlisting language="java"><![CDATA[public List<Actor> findAllActors() {
287
    return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper());
288 289
}

290
private static final class ActorMapper implements RowMapper<Actor> {
291

292
    public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
293 294
        Actor actor = new Actor();
        actor.setFirstName(rs.getString("first_name"));
295
        actor.setLastName(rs.getString("last_name"));
296
        return actor;
297 298
    }        
}]]></programlisting>
299 300 301 302 303
        </section>

        <section id="jdbc-JdbcTemplate-examples-update">
          <title>Updating (INSERT/UPDATE/DELETE)</title>

304
          <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
305 306
        "insert into t_actor (first_name, last_name) values (?, ?)", 
        "Leonor", "Watling");]]></programlisting>
307

308
          <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
309 310
        "update t_actor set = ? where id = ?", 
        "Banjo", 5276L);]]></programlisting>
311

312
          <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
313
        "delete from actor where id = ?",
314
        Long.valueOf(actorId));]]></programlisting>
315 316 317 318 319 320 321 322 323 324
        </section>

        <section id="jdbc-JdbcTemplate-examples-other">
          <title>Other operations</title>

          <para>The <methodname>execute(..)</methodname> method can be used to
          execute any arbitrary SQL, and as such is often used for DDL
          statements. It is heavily overloaded with variants taking callback
          interfaces, binding variable arrays, and suchlike.</para>

325
          <programlisting language="java"><![CDATA[this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");]]></programlisting>
326 327 328 329 330

          <para>Invoking a simple stored procedure (more sophisticated stored
          procedure support is <link linkend="jdbc-StoredProcedure">covered
          later</link>).</para>

331
          <programlisting language="java"><![CDATA[this.jdbcTemplate.update(
332
        "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", 
333
        Long.valueOf(unionId));]]></programlisting>
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
        </section>
      </section>

      <section id="jdbc-JdbcTemplate-idioms">
        <title><classname>JdbcTemplate</classname> idioms (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). To be clear, 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 idiom 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 this:</para>

363
        <programlisting language="java">public class JdbcCorporateEventDao implements CorporateEventDao {
364 365 366 367 368 369 370 371 372 373

    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>

374 375 376 377 378 379 380 381
        <para>The corresponding configuration might look like this.</para>

        <programlisting language="xml"><![CDATA[<?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
382
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
383
        http://www.springframework.org/schema/context
384
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    
    <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 the component
        scanning and annotation support for dependency injection. In this case
403
        we would annotate the setter method for the
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
        <classname>DataSource</classname> with the
        <interfacename>@Autowired</interfacename> annotation.</para>

        <para><programlisting language="java">public class JdbcCorporateEventDao implements CorporateEventDao {

    private JdbcTemplate jdbcTemplate;

    @Autowired
    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 would look like the
        following:</para>

        <para><programlisting language="xml"><![CDATA[<?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
428
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
429
        http://www.springframework.org/schema/context
430
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
    
    <!-- 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 you inherit a
        <methodname>setDataSource(..)</methodname> method for free from said
        superclass. It is totally up to you as to whether or not you inherit
        from said class, you certainly are not forced to. If you look at the
        source for the <classname>JdbcDaoSupport</classname> class you will
        see that there is not a whole lot to it... it is provided as a
        convenience only.</para>
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

        <para>Regardless of which of the above template initialization styles
        you choose to use (or not), there is (almost) certainly no need to
        create a brand new instance of a <classname>JdbcTemplate</classname>
        class each and every time you wish to execute some SQL... remember,
        once configured, a <classname>JdbcTemplate</classname> instance is
        threadsafe. A reason for wanting multiple
        <classname>JdbcTemplate</classname> instances would be when you have
        an application that 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
      will describe 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>

483
      <programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
484 485 486 487 488 489 490 491
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public int countOfActorsByFirstName(String firstName) {

492
    String sql = "select count(*) from T_ACTOR where first_name = :first_name";
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

    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>If you like, you can also pass along named parameters (and their
      corresponding values) to a
      <classname>NamedParameterJdbcTemplate</classname> instance using the
      (perhaps more familiar) <interfacename>Map</interfacename>-based style.
      (The rest of the methods exposed by the
      <interfacename>NamedParameterJdbcOperations</interfacename> - and
      implemented by the <classname>NamedParameterJdbcTemplate</classname>
      class) follow a similar pattern and will not be covered here.)</para>

513
      <programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
514 515 516 517 518 519 520 521
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public int countOfActorsByFirstName(String firstName) {

522
    String sql = "select count(*) from T_ACTOR where first_name = :first_name";
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

    Map namedParameters = Collections.singletonMap("first_name", firstName);

    return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}</programlisting>

      <para>Another nice feature related to the
      <classname>NamedParameterJdbcTemplate</classname> (and existing in the
      same Java package) is the
      <interfacename>SqlParameterSource</interfacename> interface. You have
      already seen an example of an implementation of this interface in one of
      the preceding code snippets (the
      <classname>MapSqlParameterSource</classname> class). The entire point of
      the <interfacename>SqlParameterSource</interfacename> is to serve as 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>

553
      <programlisting language="java">public class Actor {
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574

    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>

575
      <programlisting language="java"><lineannotation>// some JDBC-backed DAO class...</lineannotation>
576 577 578 579 580 581 582 583 584
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>
585 586
    String sql = 
        "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614

    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 some of the
      functionality only present in the <classname>JdbcTemplate</classname>
      class), then you can use the
      <methodname>getJdbcOperations()</methodname> method to access the
      wrapped <classname>JdbcTemplate</classname> <emphasis>via the
      <interfacename>JdbcOperations</interfacename>
      interface</emphasis>.</para>

      <para>See also the section entitled <xref
      linkend="jdbc-JdbcTemplate-idioms" /> for some advice on how to best use
      the <classname>NamedParameterJdbcTemplate</classname> class in the
      context of an application.</para>
    </section>

    <section id="jdbc-SimpleJdbcTemplate">
      <title><classname>SimpleJdbcTemplate</classname></title>

      <note>
615 616 617 618 619 620 621 622 623 624
        <para><emphasis>The idea behind the
        <classname>SimpleJdbcTemplate</classname> is to provide a simpler
        interface that takes better advantage of Java 5 features. It was
        initially the only <interfacename>JdbcOperations</interfacename>
        implementation that provided support for Java 5 enhanced syntax with
        generics and varargs. Now, in Spring 3.0, the original
        <classname>JdbcTemplate</classname> has been upgraded to Java 5 as
        well, but the <classname>SimpleJdbcTemplate</classname> still has the
        advantage of providing a simpler API when you don't need access to all
        the methods that the <classname>JdbcTemplate</classname> offers. Also,
625
        since the <classname>SimpleJdbcTemplate</classname> was designed for
626 627
        Java 5 there are more methods that take advantage of varargs due to
        different ordering of the parameters.</emphasis></para>
628 629 630
      </note>

      <para>The <classname>SimpleJdbcTemplate</classname> class is a wrapper
631 632 633
      around the classic <classname>JdbcTemplate</classname> that takes better
      advantage of Java 5 language features such as varargs and
      autoboxing.</para>
634 635 636 637 638 639 640 641 642

      <para>The value-add of the <classname>SimpleJdbcTemplate</classname>
      class in the area of syntactic-sugar is best illustrated with a
      <emphasis>'before and after'</emphasis> example. The following code
      snippet shows first some data access code using the classic
      <classname>JdbcTemplate</classname>, followed immediately thereafter by
      a code snippet that does the same job, only this time using the
      <classname>SimpleJdbcTemplate</classname>.</para>

643
      <programlisting language="java"><lineannotation>// classic <classname>JdbcTemplate</classname>-style...</lineannotation>
644 645 646 647 648 649
private JdbcTemplate jdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

650 651 652 653
public Actor findActor(String specialty, int age) {

    String sql = "select id, first_name, last_name from T_ACTOR" + 
            " where specialty = ? and age = ?";
654
    
655 656
    RowMapper&lt;Actor&gt; mapper = new RowMapper&lt;Actor&gt;() {
        public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
657 658 659 660 661 662 663
            Actor actor = new Actor();
            actor.setId(rs.getLong("id"));
            actor.setFirstName(rs.getString("first_name"));
            actor.setLastName(rs.getString("last_name"));
            return actor;
        }
    };
664

665
    
666 667
    <lineannotation>// notice the wrapping up of the argumenta in an array</lineannotation>
    return (Actor) jdbcTemplate.queryForObject(sql, new Object[] {id}, mapper);
668 669 670
}</programlisting>

      <para>Here is the same method, only this time using the
671
      <classname>SimpleJdbcTemplate</classname>.</para>
672

673
      <programlisting language="java"><lineannotation>// <classname>SimpleJdbcTemplate</classname>-style...</lineannotation>
674 675 676 677 678 679
private SimpleJdbcTemplate simpleJdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}

680
public Actor findActor(String specialty, int age) {
681

682 683 684
    String sql = "select id, first_name, last_name from T_ACTOR" + 
            " where specialty = ? and age = ?";
    RowMapper&lt;Actor&gt; mapper = new RowMapper&lt;Actor&gt;() {  
685 686 687 688 689 690 691 692 693
        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;
        }
    };

694 695 696
    <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);
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
}</programlisting>

      <para>See also the section entitled <xref
      linkend="jdbc-JdbcTemplate-idioms" /> for some advice on how to best 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 will then allow you
        to invoke the method that you want. The only downside is that the
        methods on the <interfacename>JdbcOperations</interfacename> interface
        are not generified, so you are back to casting and such again.</para>
      </note>
    </section>

    <section id="jdbc-datasource">
      <title><interfacename>DataSource</interfacename></title>

      <para>In order to work with data from a database, one needs to obtain a
      connection to the database. The way Spring does this is through a
      <interfacename>DataSource</interfacename>. A
      <interfacename>DataSource</interfacename> is part of the JDBC
      specification and can be seen as a generalized connection factory. It
      allows a container or a framework to hide connection pooling and
      transaction management issues from the application code. As a developer,
      you don not need to know any details about how to connect to the
      database, that is the responsibility for the administrator that sets up
      the datasource. You will most likely have to fulfill both roles while
      you are developing and testing you code though, but you will not
      necessarily have to know how the production data source is
      configured.</para>

      <para>When using Spring's JDBC layer, you can either obtain a data
737 738 739 740
      source from JNDI or you can configure your own, using a connection pool
      implementation provided by a third party. Popular ones are Apache
      Jakarta Commons DBCP and C3P0. There are some implementations provided
      in the Spring distribution, but they are only meant to be used for
741
      testing purposes since they don't provide any pooling.</para>
742 743 744 745 746 747 748 749 750 751 752 753 754 755

      <para>We will use the <classname>DriverManagerDataSource</classname>
      implementation for this section but there are several additional
      implementations that will be covered later on. The
      <classname>DriverManagerDataSource</classname> works the same way that
      you probably are used to work when you obtain a JDBC connection. You
      have to specify the fully qualified class name of the JDBC driver that
      you are using so that the <classname>DriverManager</classname> can load
      the driver class. Then you have to provide a URL that varies between
      JDBC drivers. You have to consult the documentation for your driver for
      the correct value to use here. Finally you must provide a username and a
      password that will be used to connect to the database. Here is an
      example of how to configure a
      <classname>DriverManagerDataSource</classname> in Java code:</para>
756

757
      <programlisting language="java"><![CDATA[DriverManagerDataSource dataSource = new DriverManagerDataSource();
758 759 760
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
761
dataSource.setPassword("");]]></programlisting>
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

      <para>We also have an example how this would look in an XML
      configuration:</para>

      <programlisting language="java"><![CDATA[<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>

      <note>
        <para>The <classname>DriverManagerDataSource</classname> class should
777 778
        only be used for testing purposes since it does not provide pooling
        and will perform poorly when multiple requests for a connection are
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
        made.</para>
      </note>

      <para>Just to provide a more complete picture we will also show the
      configuration for DBCP and C3P0. We only show the basic connectivity
      configuration here. There are more options documented in the product
      documentation for the respective connection pooling implementations that
      will help control the pooling features.</para>

      <para>FIrst we have the DBCP configuration:</para>

      <programlisting language="java"><![CDATA[<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>And last we have the C3P0 configuration:</para>

      <programlisting language="java"><![CDATA[<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>
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
    </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
      data-access-strategy-agnostic
      <classname>org.springframework.dao.DataAccessException</classname>.
      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.
      More precise than <literal>SQLState</literal> implementation, but vendor
      specific. The error code translations are based on codes held in a
      JavaBean type class named <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 DatabaseProductName taken
      from the <interfacename>DatabaseMetaData</interfacename>, the codes for
      the current database are used.</para>

      <para>The <classname>SQLErrorCodeSQLExceptionTranslator</classname>
      applies the following matching rules: <itemizedlist spacing="compact">
          <listitem>
            <para>Try custom translation implemented by any subclass. Note
            that this class is concrete and is typically used itself, in which
            case this rule does not apply.</para>
          </listitem>

          <listitem>
            <para>Apply error code matching. Error codes are obtained from the
            <classname>SQLErrorCodesFactory</classname> by default. This looks
            up error codes from the classpath and keys into them from the
            database name from the database metadata.</para>
          </listitem>

          <listitem>
            <para>Use the fallback translator.
            <classname>SQLStateSQLExceptionTranslator</classname> is the
            default fallback translator.</para>
          </listitem>
        </itemizedlist></para>

      <para><classname>SQLErrorCodeSQLExceptionTranslator</classname> can be
      extended the following way:</para>

865
      <programlisting language="java"><![CDATA[public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
866 867 868 869 870 871 872

    protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
        if (sqlex.getErrorCode() == -12345) {
            return new DeadlockLoserDataAccessException(task, sqlex);
        }
        return null;
    }
873
}]]></programlisting>
874 875 876 877 878 879 880 881 882 883 884

      <para>In this example the specific error code
      <literal>'-12345'</literal> is translated and any other errors are
      simply left to be translated by the default translator implementation.
      To use this custom translator, it is necessary to pass it to the
      <classname>JdbcTemplate</classname> using 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>

885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
      <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>
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921

      <para>The custom translator is passed a data source because we still
      want the default translation 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>To execute an SQL statement, there is very little code needed. All
      you need is a <interfacename>DataSource</interfacename> and a
      <classname>JdbcTemplate</classname>. Once you have that, you can use a
      number of convenience methods that are provided with the
      <classname>JdbcTemplate</classname>. Here is a short example showing
      what you need to include for a minimal but fully functional class that
      creates a new table.</para>

922
      <programlisting language="java"><![CDATA[import javax.sql.DataSource;
923 924 925 926 927 928 929 930 931 932 933 934 935
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))");
    }
936
}]]></programlisting>
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
    </section>

    <section id="jdbc-statements-querying">
      <title>Running Queries</title>

      <para>In addition to the execute methods, there is a large number of
      query methods. Some of these methods are intended to be used for queries
      that return a single value. Maybe you want to retrieve a count or a
      specific value from one row. If that is the case then you can use
      <methodname>queryForInt(..)</methodname>,
      <methodname>queryForLong(..)</methodname> or
      <methodname>queryForObject(..)</methodname>. The latter will convert 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> will
      be 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>

956
      <programlisting language="java"><![CDATA[import javax.sql.DataSource;
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
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;
    }
978
}]]></programlisting>
979 980 981 982 983 984 985 986 987 988 989

      <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
      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 we add a method to the
      above example to retrieve a list of all the rows, it would look like
      this:</para>

990
      <programlisting language="java"><![CDATA[
991 992 993 994 995 996
private JdbcTemplate jdbcTemplate;

public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

997
public List<Map<String, Object>> getList() {
998
    return this.jdbcTemplate.queryForList("select * from mytable");
999
}]]></programlisting>
1000 1001 1002

      <para>The list returned would look something like this:</para>

1003
      <programlisting><![CDATA[[{name=Bob, id=1}, {name=Mary, id=2}]]]></programlisting>
1004 1005 1006 1007 1008 1009 1010 1011
    </section>

    <section id="jdbc-updates">
      <title>Updating the database</title>

      <para>There are also a number of update methods that you can use. Find
      below an example where a column is updated for a certain primary key. In
      this example an SQL statement is used that has place holders for row
1012 1013 1014 1015
      parameters. Note that the parameter values can be passed in as varargs
      or alternatively as an array of objects (and thus primitives should
      either be wrapped in the primitive wrapper classes either explicitly or
      using auto-boxing).</para>
1016

1017
      <programlisting language="java"><![CDATA[import javax.sql.DataSource;
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031

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 = ?", 
1032
                name, id);
1033
    }
1034
}]]></programlisting>
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
    </section>

    <section id="jdbc-auto-genereted-keys">
      <title>Retrieving auto-generated keys</title>

      <para>One of the <methodname>update</methodname> convenience methods
      provides support for acquiring the primary keys generated by the
      database (part of the JDBC 3.0 standard - see chapter 13.6 of the
      specification for details). The method takes a
      <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 will contain
      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). An example that works on Oracle and may not
      work on other platforms is:</para>

1053
      <programlisting language="java">final String INSERT_SQL = "insert into my_test (name) values(?)";
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
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-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 has support for thread-bound connections, for example for
      use with <classname>DataSourceTransactionManager</classname>.</para>
    </section>

    <section id="jdbc-SmartDataSource">
      <title><interfacename>SmartDataSource</interfacename></title>

      <para>The <interfacename>SmartDataSource</interfacename> interface is to
      be implemented by classes that can provide a connection to a relational
      database. Extends the <interfacename>DataSource</interfacename>
      interface to allow classes using it to query whether or not the
      connection should be closed after a given operation. This can sometimes
      be useful for efficiency, in the cases where one knows that one wants to
      reuse a connection.</para>
    </section>

    <section id="jdbc-AbstractDataSource">
      <title><classname>AbstractDataSource</classname></title>

      <para>This is an <literal>abstract</literal> base class for Spring's
      <interfacename>DataSource</interfacename> implementations, that takes
      care of the "uninteresting" glue. This is the class one would extend if
      one was writing one's own <interfacename>DataSource</interfacename>
      implementation.</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 use. Obviously, this is not
      multi-threading capable.</para>

      <para>If client code will call close in the assumption of a pooled
      connection, like when using persistence tools, set
      <literal>suppressClose</literal> to <literal>true</literal>. This will
      return a close-suppressing proxy instead of the physical connection. Be
      aware that you will not be able to cast this to a native Oracle
      <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>
1137 1138 1139
      interface that configures a plain old JDBC Driver via bean properties,
      and returns a new <interfacename>Connection</interfacename> every
      time.</para>
1140 1141

      <para>This is potentially useful for test or standalone environments
T
Thomas Risberg 已提交
1142
      outside of a Java EE container, either as a
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
      <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
      commons-dbcp 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
T
Thomas Risberg 已提交
1162
      by a Java EE server.</para>
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191

      <note>
        <para>It should almost never be necessary or desirable to use this
        class, except when existing code exists which must be called and
        passed a standard JDBC <interfacename>DataSource</interfacename>
        interface implementation. In this case, it's possible to still have
        this code be usable, but participating in Spring managed transactions.
        It is generally preferable to write your own new code using the higher
        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 to retrieve the JDBC connection via
      <literal>DataSourceUtils.getConnection(DataSource)</literal> instead of
T
Thomas Risberg 已提交
1192
      Java EE's standard <literal>DataSource.getConnection</literal>. This is
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
      recommended anyway, as 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 <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. Note that JTA does not support
      custom isolation levels!</para>
    </section>

    <section id="jdbc-NativeJdbcExtractor">
      <title>NativeJdbcExtractor</title>

      <para>There are times when we need to access vendor specific JDBC
      methods that differ from the standard JDBC API. This can be problematic
      if we are running in an application server or with a
      <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 NativeJdbcExtractor 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 Java Docs 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 will cover
    batch processing using both the JdbcTemplate and the
    SimpleJdbcTemplate.</para>

    <section id="jdbc-advanced-classic">
      <title>Batch operations with the JdbcTemplate</title>

      <para>Using the JdbcTemplate batch processing is accomplished by
      implementing a special interface,
      <classname>BatchPreparedStatementSetter</classname>, and passing that in
      as the second parameter in your <classname>batchUpdate</classname>
      method call. This interface has two methods you must implement. One is
      named <classname>getBatchSize</classname> and here you provide the size
      of the current batch. The other method is
      <classname>setValues</classname> and it allows you to set the values for
      the parameters of the prepared statement and. This method will get
      called the number of times that you specified in the
      <classname>getBatchSize</classname> call. Here is an example of this
      where we update the actor table based on entries in a list. The entire
      list is used as the batch in his example.</para>

1294
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1295 1296 1297 1298 1299 1300
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

1301
    public int[] batchUpdate(final List<Actor> actors) {
1302 1303 1304 1305
        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 {
1306 1307 1308
                        ps.setString(1, actors.get(i).getFirstName());
                        ps.setString(2, actors.get(i).getLastName());
                        ps.setLong(3, actors.get(i).getId().longValue());
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
                    }

                    public int getBatchSize() {
                        return actors.size();
                    }
                } );
        return updateCounts;
    }

    //  ... additional methods
1319
}]]></programlisting>If you are processing stream of updates or reading from a
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
      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 simply provide all parameter values in the
      call and the framework will loop over these values and use an internal
      prepared statement setter. The API varies depending on whether you use
      named parameters or not. For the named parameters you provide an array
      of <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>

1345
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1346 1347 1348 1349 1350 1351
    private SimpleJdbcTemplate simpleJdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

1352
    public int[] batchUpdate(final List<Actor> actors) {
1353 1354
        SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());
        int[] updateCounts = simpleJdbcTemplate.batchUpdate(
1355 1356
            "update t_actor set first_name = :firstName, last_name = :lastName where id = :id",
            batch);
1357 1358 1359 1360
        return updateCounts;
    }

    //  ... additional methods
1361 1362 1363
}]]></programlisting>For an SQL statement using the classic "?" place holders
      you pass in a List containing an object array with the update values.
      This object array must have one entry for each placeholder in the SQL
1364 1365 1366 1367 1368
      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 "?" place holders:</para>

1369
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1370 1371 1372 1373 1374 1375
    private SimpleJdbcTemplate simpleJdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    }

1376 1377
    public int[] batchUpdate(final List<Actor> actors) {
        List<Object[]> batch = new ArrayList<Object[]>();
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
        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
1392 1393 1394
}]]></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 and it's not always available in which case the JDBC
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
      driver simply 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 simplified
    configuration by taking advantage of database metadata that can be
    retrieved via the JDBC driver. This means there is less to configure up
    front, although you can override or turn off the metadata processing if
    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 first. We will use the
      minimal amount of configuration options to start with. The
      <classname>SimpleJdbcInsert</classname> should be instantiated in the
      data access layer's initialization method. For this example, the
      initializing method is the <classname>setDataSource</classname> method.
      There is no need to subclass the <classname>SimpleJdbcInsert</classname>
      class, just create a new instance and set the table name using the
      <classname>withTableName</classname> method. Configuration methods for
      this class follows the "fluid" style returning the instance of the
      <classname>SimpleJdbcInsert</classname> which allows you to chain all
      configuration methods. In this case there is only one configuration
      method used but we will see examples of multiple ones soon.</para>

1426
      <programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
    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) {
1437
        Map<String, Object> parameters = new HashMap<String, Object>(3);
1438 1439 1440 1441 1442 1443 1444
        parameters.put("id", actor.getId());
        parameters.put("first_name", actor.getFirstName());
        parameters.put("last_name", actor.getLastName());
        insertActor.execute(parameters);
    }

    //  ... additional methods
1445
}]]></programlisting>
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464

      <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>Next we'll look at the same insert, but instead of passing in the
      id we will retrieve the auto-generated key and set it on the new Actor
      object. When we create the <classname>SimpleJdbcInsert</classname>, in
      addition to specifying the table name, we specify the name of the
      generated key column using the
      <classname>usingGeneratedKeyColumns</classname> method.</para>

1465
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
    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) {
1478
        Map<String, Object> parameters = new HashMap<String, Object>(2);
1479 1480 1481 1482 1483 1484 1485
        parameters.put("first_name", actor.getFirstName());
        parameters.put("last_name", actor.getLastName());
        Number newId = insertActor.executeAndReturnKey(parameters);
        actor.setId(newId.longValue());
    }

    //  ... additional methods
1486
}]]></programlisting>Here we can see the main difference when executing the
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
      insert is that we don't add the id to the Map and we call the
      <literal>executeReturningKey</literal> method. This returns a
      <literal>java.lang.Number</literal> object that we can use to create an
      instance of the numerical type that is used in our domain class. It's
      important to note that we can't rely on all databases to return a
      specific Java class here, <literal>java.lang.Number</literal> is the
      base class that we can rely on. If you have multiple auto-generated
      columns or the generated values are non-numeric then you can use a
      <literal>KeyHolder</literal> that is returned from the
      <literal>executeReturningKeyHolder</literal> method.</para>
    </section>

    <section id="jdbc-simple-jdbc-insert-3">
      <title>Specifying the columns to use for a SimpleJdbcInsert</title>

      <para>It's possible to limit the columns used for the insert by
      specifying a list of column names to be used. This is accomplished using
      the <classname>usingColumns</classname> method.</para>

1506
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
    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) {
1520
        Map<String, Object> parameters = new HashMap<String, Object>(2);
1521 1522 1523 1524 1525 1526 1527
        parameters.put("first_name", actor.getFirstName());
        parameters.put("last_name", actor.getLastName());
        Number newId = insertActor.executeAndReturnKey(parameters);
        actor.setId(newId.longValue());
    }

    //  ... additional methods
1528 1529
}]]></programlisting>The execution of the insert is the same as if we had
      relied on the metadata for determining what columns to use.</para>
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
    </section>

    <section id="jdbc-simple-jdbc-parameters">
      <title>Using SqlParameterSource to provide parameter values</title>

      <para>Using a Map to provide parameter values works fine, but it's not
      the most convenient class to use. Spring provides a couple of
      implementations of the <classname>SqlParameterSource</classname>
      interface that can be used instead. The first one we'll look at is
      <classname>BeanPropertySqlParameterSource</classname> which is a very
      convenient class as long as you have a JavaBean compliant class that
      contains your values. It will use the corresponding getter method to
      extract the parameter values. Here is an example:</para>

1544
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
    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
1563
}]]></programlisting>Another option is the
1564 1565 1566 1567
      <classname>MapSqlParameterSource</classname> that resembles a Map but
      provides a more convenient <classname>addValue</classname> method that
      can be chained.</para>

1568
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
    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
1589 1590
}]]></programlisting>As you can see, the configuration is the same, it;s just
      the executing code that has to change to use these alternative input
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
      classes.</para>
    </section>

    <section id="jdbc-simple-jdbc-call-1">
      <title>Calling a stored procedure using SimpleJdbcCall</title>

      <para>Let's now turn our attention to calling stored procedures using
      the <classname>SimpleJdbcCall</classname> class. This class is designed
      to make it as simple as possible to call a stored procedure. It takes
      advantage of metadata present in the database to look up names of in and
      out parameters. This means that you don't have to explicitly declare
      parameters. You can of course still declare them if you prefer to do
      that or if you have parameters that don't have an automatic mapping to a
      Java class like ARRAY or STRUCT parameters. In our first example we will
      look at a plain vanilla procedure that only returns scalar values in
      form of VARCHAR and DATE. I have added a birthDate property to the Actor
      class to get some variety in terms of return values. The example
      procedure reads a specified actor entry and returns first_name,
      last_name, and birth_date columns in the form of out parameters. Here is
      the source for the procedure as it would look when using MySQL as the
      database:</para>

1613
      <para><programlisting><![CDATA[CREATE PROCEDURE read_actor ( 
1614 1615 1616 1617 1618 1619 1620 1621
  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;
1622
END;]]></programlisting>As you can see there are four parameters. One is an in
1623 1624 1625 1626 1627 1628 1629 1630 1631
      parameter "in_id" containing the id of the Actor we are looking up. The
      remaining parameters are out parameters and they will be used to return
      the data read from the table.</para>

      <para>The <classname>SimpleJdbcCall</classname> is declared in a similar
      manner to the <classname>SimpleJdbcInsert</classname>, no need to
      subclass and we declare it in the initialization method. For this
      example, all we need to specify is the name of the procedure.</para>

1632
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
    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
1656
}]]></programlisting>The execution of the call involves creating an
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
      <classname>SqlParameterSource</classname> containing the in parameter.
      It's important to match the name of the parameter declared in the stored
      procedure. The case doesn't have to match since we use metadata to
      determine how database objects should be referred to - what you specify
      in your source for the stored procedure is not necessarily the way it is
      stored in the database, some databases transform names to all upper case
      while others use lower case or the case as specified.</para>

      <para>The <classname>execute</classname> method takes the in parameters
      and returns a Map containing any out parameters keyed by the name as
      specified in the stored procedure. In this case they are
      <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 just
      creates an Actor instance to use to return the data retrieved. Again,
      it's important to match the names of the out parameters here. Also, the
      case used for the names of the out parameters stored in the results map
      are as they were defined in the database. You will either have to do a
      case-insensitive lookup or instruct Spring to use a
      <classname>CaseInsensitiveMap</classname> from the Jakarta Commons
      project. The way you do that is by creating your own
      <classname>JdbcTemplate</classname> and setting 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 also have to include the
      <classname>commons-collections.jar</classname> on your classpath for
      this to work. Here is an example of this configuration:</para>

1687
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
    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
1700 1701
}]]></programlisting>By doing this, you don't have to worry about the case
      used for the names of your returned out parameters.</para>
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
    </section>

    <section id="jdbc-simple-jdbc-call-2">
      <title>Declaring parameters to use for a SimpleJdbcCall</title>

      <para>We have seen how the parameters are deduced based on metadata, but
      you can declare then explicitly if you wish. This is done when the
      <classname>SimpleJdbcCall</classname> is created and configured using
      the <classname>declareParameters</classname> method that 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>.</para>

      <para>We can opt to declare one, some or all of the parameters
      explicitly. The parameter metadata is still being used. By calling the
      method <classname>withoutProcedureColumnMetaDataAccess</classname> we
      can specify that we would like to bypass any processing of the metadata
      lookups for potential parameters and only use the declared ones. Another
      situation that can arise is that one or more in parameters have default
      values and we would like to leave them out of the call. To do that we
      will just call the <classname>useInParameterNames</classname> to specify
      the list of in parameter names to include.</para>

      <para>This is what a fully declared procedure call declaration of our
      earlier example would look like:</para>

1728
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748
    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
1749
}]]></programlisting>The execution and end results are the same, we are just
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768
      specifying all the details explicitly rather than relying on metadata.
      This will be necessary if the database we use is not part of the
      supported databases. Currently we support metadata lookup of stored
      procedure calls for the following databases: Apache Derby, DB2, MySQL,
      Microsoft SQL Server, Oracle and Sybase. We also support metadata lookup
      of stored functions for: MySQL, Microsoft SQL Server and Oracle.</para>
    </section>

    <section id="jdbc-params">
      <title>How to define SqlParameters</title>

      <para>To define a parameter to be used for the SimpleJdbc classes, and
      also for the RDBMS operations classes covered in the following section,
      you use an <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>

1769 1770
      <para><programlisting language="java"><![CDATA[   new SqlParameter("in_id", Types.NUMERIC),
   new SqlOutParameter("out_first_name", Types.VARCHAR),]]></programlisting></para>
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789

      <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 out parameter to be used in a stored procedure call. There
      is also an <classname>SqlInOutParameter</classname> for inout
      parameters, parameters that provide an in 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
1790
        parameters declared as <classname>SqlOutParameter</classname>.</para>
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
      </note>

      <para>In addition to the name and the SQL type you can specify
      additional options. For in parameters you can specify a scale for
      numeric data or a type name for custom database types. For out
      parameters you can provide a <classname>RowMapper</classname> to handle
      mapping of rows returned from a REF cursor. Another option is to specify
      an <classname>SqlReturnType</classname> that provides and 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>Calling a stored function is done almost exactly the same way as
      calling a stored procedure. The only difference is that you need to
      provide a function name rather than a procedure name. This is done by
      using the <classname>withFunctionName</classname> method. Using this
      method indicates that your call is to a function and the corresponding
      call string for a function call will be generated. There is also a
      specialized execute call <classname>executeFunction</classname> that
      will return the function return value as an object of a specified type.
      This way you don't have to retrieve the return value from the results
      map. A similar convenience method named
      <classname>executeObject</classname> is also available for stored
      procedures that only have one out 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>

1821
      <para><programlisting><![CDATA[CREATE FUNCTION get_actor_name (in_id INTEGER)
1822 1823 1824 1825 1826 1827 1828
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;
1829
END;]]></programlisting></para>
1830 1831 1832 1833 1834

      <para>To call this function we again create a
      <classname>SimpleJdbcCall</classname> in the initialization
      method.</para>

1835
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855
    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
1856
}]]></programlisting>The execute method used returns a
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
      <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
      has always been a bit tricky. Some databases return result sets during
      the JDBC results processing while others require an explicitly
      registered out parameter of a specific type. Both approaches still needs
      some additional processing to loop over the result set and process the
      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 you declare the
      <classname>RowMapper</classname> implementations. The name specified
      will still be used to store the processed list of results in the results
      map returned from the execute statement.</para>

      <para>For this example we will use 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>

1883
      <para><programlisting><![CDATA[CREATE PROCEDURE read_all_actors()
1884 1885
BEGIN
 SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a;
1886
END;]]></programlisting>In order to call this procedure we need to declare the
1887 1888 1889 1890 1891 1892
      <classname>RowMapper</classname> to be used. Since the class we want to
      map to follows the JavaBean rules, we 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>

1893
      <para><programlisting language="java"><![CDATA[public class JdbcActorDao implements ActorDao {
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
    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() {
1909
        Map m = procReadAllActors.execute(new HashMap<String, Object>(0));
1910 1911 1912 1913
        return (List) m.get("actors");
    }

    //  ... additional methods
1914
}]]></programlisting>The execute call passes in an empty Map since this call
1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971
      doesn't 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 one to access the database in a more
    object-oriented manner. By way of an example, one can execute queries and
    get the results back as a list containing business objects with the
    relational column data mapped to the properties of the business object.
    One can also execute stored procedures and run update, delete and insert
    statements.</para>

    <note>
      <para>There is a view borne from experience acquired in the field
      amongst some of the Spring developers 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 use
      and plain easier to read a DAO method that simply calls a method on a
      <classname>JdbcTemplate</classname> direct (as opposed to encapsulating
      a query as a full-blown class).</para>

      <para>It must be stressed however that this is just a
      <emphasis>view</emphasis>... if you feel that you are getting measurable
      value from using the RDBMS operation classes, feel free to 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 since 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
1972 1973 1974 1975
      supplied <interfacename>ResultSet</interfacename> into an object of the
      type specified. Below is a brief example of a custom query that maps the
      data from the t_actor relation to an instance of the
      <classname>Actor</classname> class.</para>
1976

1977
      <programlisting language="java"><![CDATA[public class ActorMappingQuery extends MappingSqlQuery<Actor> {
1978

1979 1980
    public ActorMappingQuery(DataSource ds) {
        super(ds, "select id, first_name, last_name from t_actor where id = ?");
1981 1982 1983 1984
        super.declareParameter(new SqlParameter("id", Types.INTEGER));
        compile();
    }

1985 1986 1987 1988 1989 1990 1991 1992 1993
    @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;
    }

1994
}]]></programlisting>
1995

1996 1997 1998
      <para>The class extends <classname>MappingSqlQuery</classname>
      parameterized with the <classname>Actor</classname> type. We provide a
      constructor for this customer query that takes the
1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
      <interfacename>DataSource</interfacename> as the only parameter. In this
      constructor we 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. Each parameter must be declared using the
      <literal>declareParameter</literal> method passing in an
      <classname>SqlParameter</classname>. The
      <classname>SqlParameter</classname> takes a name and the JDBC type as
      defined in <classname>java.sql.Types</classname>. After all parameters
      have been defined we call the <literal>compile()</literal> method so the
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
      statement can be prepared and later be executed. This class is thread
      safe once it has been compiled, so as long as these classes are created
      when the DAO is initialized they can be kept as instance variable and be
      reused.</para>

      <programlisting language="java"><![CDATA[private ActorMappingQuery actorMappingQuery;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.actorMappingQuery = new ActorMappingQuery(dataSource);
}

public Customer getCustomer(Long id) {
    return actorMappingQuery.findObject(id);
2025
}]]></programlisting>
2026 2027

      <para>The method in this example retrieves the customer with the id that
2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
      is passed in as the only parameter. Since we only want one object
      returned we simply call the convenience method findObject with the id as
      parameter. If we instead had a query the returned a list of objects and
      took additional parameters then we would use one of the execute methods
      that takes an array of parameter values passed in as varargs.</para>

      <programlisting language="java"><![CDATA[public List<Actor> searchForActors(int age, String namePattern) {
    List<Actor> actors = actorSearchMappingQuery.execute(age, namePattern);
    return actors;
}]]></programlisting>
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
    </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. This
      class is concrete. Although it can be subclassed (for example to add a
2050 2051 2052
      custom update method - like in this example where we call it execute) it
      can easily be parameterized by setting SQL and declaring
      parameters.</para>
2053

2054
      <programlisting language="java"><![CDATA[import java.sql.Types;
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065

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 = ?");
2066 2067
        declareParameter(new SqlParameter("creditRating", Types.NUMERIC));
        declareParameter(new SqlParameter("id", Types.NUMERIC));
2068 2069 2070
        compile();
    }

2071
    /**
2072 2073 2074
     * @param id for the Customer to be updated
     * @param rating the new value for credit rating
     * @return number of rows updated
2075 2076 2077
     */
    public int execute(int id, int rating) {
        return update(rating, id);
2078
    }
2079
}]]></programlisting>
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094
    </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>

2095
      <para>To define a parameter to be used for the StoredProcedure class,
2096 2097 2098 2099 2100
      you use an <classname>SqlParameter</classname> or one of its subclasses.
      You must 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>

2101 2102
      <para><programlisting language="java"><![CDATA[   new SqlParameter("in_id", Types.NUMERIC),
   new SqlOutParameter("out_first_name", Types.VARCHAR),]]></programlisting></para>
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116

      <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 out parameter to be used in the stored procedure call. There
      is also an <classname>SqlInOutParameter</classname> for inout
      parameters, parameters that provide an in value to the procedure and
      that also return a value</para>

      <para><note>
2117 2118
          <para>Parameters declared as <classname>SqlParameter</classname> and
          <classname>SqlInOutParameter</classname> will always be used to
2119 2120
          provide input values. In addition to this any parameter declared as
          <classname>SqlOutParameter</classname> where an non-null input value
2121
          is provided will also be used as an input parameter.</para>
2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
        </note></para>

      <para>In addition to the name and the SQL type you can specify
      additional options. For in parameters you can specify a scale for
      numeric data or a type name for custom database types. For out
      parameters you can provide a <classname>RowMapper</classname> to handle
      mapping of rows returned from a REF cursor. Another option is to specify
      an <classname>SqlReturnType</classname> that provides and opportunity to
      define customized handling of the return values.</para>

2132 2133
      <para>Here is an example of a simple DAO that uses a
      <classname>StoredProcedure</classname> to call a function,
2134
      <literal>sysdate()</literal>, that comes with any Oracle database. To
2135 2136 2137 2138 2139 2140
      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 would
      declare it as a top-level class. There are no input parameters in this
      example, but there is an output parameter that is declared as a date
2141
      type using the class <classname>SqlOutParameter</classname>. The
2142 2143 2144 2145 2146 2147 2148 2149
      <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"><![CDATA[import java.sql.Types;
import java.util.Date;
2150 2151 2152 2153 2154
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

2155
import org.springframework.beans.factory.annotation.Autowired;
2156 2157 2158
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.object.StoredProcedure;

2159
public class StoredProcedureDao {
2160

2161 2162 2163 2164 2165
    private GetSysdateProcedure getSysdate;
    
    @Autowired
    public void init(DataSource dataSource) {
        this.getSysdate = new GetSysdateProcedure(dataSource);
2166 2167
    }
    
2168 2169
    public Date getSysdate() {
        return getSysdate.execute();
2170 2171
    }

2172
    private class GetSysdateProcedure extends StoredProcedure {
2173 2174 2175
        
        private static final String SQL = "sysdate";

2176 2177
        public GetSysdateProcedure(DataSource dataSource) {
            setDataSource(dataSource);
2178 2179 2180 2181 2182 2183
            setFunction(true);
            setSql(SQL);
            declareParameter(new SqlOutParameter("date", Types.DATE));
            compile();
        }

2184 2185 2186 2187 2188
        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;    
2189 2190 2191
        }
    }

2192
}]]></programlisting>
2193

2194
      <para>Below is an example of a <classname>StoredProcedure</classname>
2195 2196
      that has two output parameters (in this case Oracle REF cursors).</para>

2197
      <programlisting language="java"><![CDATA[import oracle.jdbc.OracleTypes;
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
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();
    }

2216 2217 2218
    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>());
2219
    }
2220
}]]></programlisting>
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230

      <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 in the interest of completeness.)</para>

2231
      <para>First the <classname>TitleMapper</classname> class, which simply
2232 2233 2234 2235
      maps a <interfacename>ResultSet</interfacename> to a
      <classname>Title</classname> domain object for each row in the supplied
      <interfacename>ResultSet</interfacename>.</para>

2236
      <programlisting language="java"><![CDATA[import org.springframework.jdbc.core.RowMapper;
2237 2238 2239 2240

import java.sql.ResultSet;
import java.sql.SQLException;

2241 2242 2243
import com.foo.domain.Title;

public final class TitleMapper implements RowMapper<Title> {
2244
    
2245
    public Title mapRow(ResultSet rs, int rowNum) throws SQLException {
2246 2247 2248 2249 2250
        Title title = new Title();
        title.setId(rs.getLong("id"));
        title.setName(rs.getString("name"));
        return title;
    }
2251
}]]></programlisting>
2252

2253 2254
      <para>Second, the <classname>GenreMapper</classname> class, which again
      simply maps a <interfacename>ResultSet</interfacename> to a
2255 2256 2257
      <classname>Genre</classname> domain object for each row in the supplied
      <interfacename>ResultSet</interfacename>.</para>

2258
      <programlisting language="java"><![CDATA[import org.springframework.jdbc.core.RowMapper;
2259 2260 2261 2262 2263 2264

import java.sql.ResultSet;
import java.sql.SQLException;

import com.foo.domain.Genre;

2265
public final class GenreMapper implements RowMapper<Genre> {
2266
    
2267
    public Genre mapRow(ResultSet rs, int rowNum) throws SQLException {
2268 2269
        return new Genre(rs.getString("name"));
    }
2270
}]]></programlisting>
2271

2272
      <para>If you need to pass parameters to a stored procedure (that is the
2273
      stored procedure has been declared as having one or more input
2274
      parameters in its definition in the RDBMS), you should code a strongly
2275 2276 2277 2278
      typed <literal>execute(..)</literal> method which would delegate to the
      superclass' (untyped) <literal>execute(Map parameters)</literal> (which
      has <literal>protected</literal> access); for example:</para>

2279
      <programlisting language="java"><![CDATA[import oracle.jdbc.OracleTypes;
2280
import org.springframework.jdbc.core.SqlOutParameter;
2281
import org.springframework.jdbc.core.SqlParameter;
2282 2283 2284
import org.springframework.jdbc.object.StoredProcedure;

import javax.sql.DataSource;
2285 2286 2287

import java.sql.Types;
import java.util.Date;
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
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();
    }

2303 2304
    public Map<String, Object> execute(Date cutoffDate) {
        Map<String, Object> inputs = new HashMap<String, Object>();
2305 2306 2307
        inputs.put(CUTOFF_DATE_PARAM, cutoffDate);
        return super.execute(inputs);
    }
2308
}]]></programlisting>
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438
    </section>
  </section>

  <section id="jdbc-parameter-handling">
    <title>Common issues with parameter and data value handling</title>

    <para>There are some issues involving parameters and data values that are
    common across all the different approaches provided by the Spring JDBC
    Framework.</para>

    <section id="jdbc-type-information">
      <title>Providing SQL type information for parameters</title>

      <para>Most of the time Spring will assume the SQL type of the parameters
      based on the type of parameter passed in. It is possible to explicitly
      provide the SQL type to be used when setting parameter values. This is
      sometimes necessary to correctly set NULL values.</para>

      <para>There are a few different ways this can be accomplished:</para>

      <itemizedlist>
        <listitem>
          <para>Many of the update and query methods of the
          <classname>JdbcTemplate</classname> take an additional parameter in
          the form of an int array. This array should contain the SQL type
          using constant values from the <classname>java.sql.Types</classname>
          class. There must be one entry for each parameter.</para>
        </listitem>
      </itemizedlist>

      <itemizedlist>
        <listitem>
          <para>You can wrap the parameter value that needs this additional
          information using the <classname>SqlParameterValue</classname>
          class. Create a new instance for each value and pass in the SQL type
          and parameter value in the constructor. You can also provide an
          optional scale parameter for numeric values.</para>
        </listitem>
      </itemizedlist>

      <itemizedlist>
        <listitem>
          <para>For methods working with named parameters, you can 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 and other binary objects as well and large
      chunks of text. These large object are called BLOB for binary data and
      CLOB for character data. Spring lets you handle these large objects
      using the JdbcTemplate directly and also when using the higher
      abstractions provided by RDBMS Objects and the SimpleJdbc classes. All
      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>, via the
      <classname>getLobCreator</classname> method, for creating new LOB
      objects to be inserted.</para>

      <para>The <classname>LobCreator/LobHandler</classname> provides the
      following support for LOB in- 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>We will now show an example of how to create and insert a BLOB. We
      will later see how to read it back from the database.</para>

      <para>This example uses a JdbcTemplate and an implementation of the
      AbstractLobCreatingPreparedStatementCallback. There is one method that
      must be implemented and it is "setValues". In this method you will be
      provided with a LobCreator that can be used to set the values for the
      LOB columns in your SQL insert statement.</para>

      <para>We are assuming that we have a variable named 'lobHandler' that
      already is set to an instance of a
      <classname>DefaultLobHandler</classname>. This is typically done using
      dependency injection.</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>

2439
        <programlisting language="java"><![CDATA[final File blobIn = new File("spring2004.jpg");
2440 2441 2442 2443 2444 2445
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 (?, ?, ?)",
2446
  new AbstractLobCreatingPreparedStatementCallback(lobHandler) {
2447 2448 2449 2450 2451 2452 2453 2454 2455
      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();
2456
clobReader.close();]]></programlisting>
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487

        <calloutlist>
          <callout arearefs="jdbc.lobhandler.variableref">
            <para>Here we use the lobHandler that in this example is a plain
            <classname>DefaultLobHandler</classname></para>
          </callout>

          <callout arearefs="jdbc.lobhandler.setClob">
            <para>Using the method <classname>setClobAsCharacterStream
            </classname>we pass in the contents of the CLOB</para>
          </callout>

          <callout arearefs="jdbc.lobhandler.setBlob">
            <para>Using the method
            <classname>setBlobAsBinartStream</classname> we 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, we
      use a JdbcTempate and we have the same instance variable 'lobHandler'
      with 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>

2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
          <programlisting language="java"><![CDATA[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;
          }
        });
2499
]]></programlisting>
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566

          <calloutlist>
            <callout arearefs="jdbc.lobhandler.setClob">
              <para>Using the method <classname>getClobAsString </classname>we
              retrieve the contents of the CLOB</para>
            </callout>

            <callout arearefs="jdbc.lobhandler.setBlob">
              <para>Using the method <classname>getBlobAsBytes</classname> we
              retrieve the contents of the BLOB</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
      "select * from T_ACTOR where id in (1, 2, 3)". This variable list is not
      directly supported for prepared statements by the JDBC standard - there
      is no way of declaring a variable number of place holders. You would
      have to either have a number of variations with the desired number of
      place holders prepared or you would have to dynamically generate the SQL
      string once you know how many place holders are required. The named
      parameter support provided in the
      <classname>NamedParameterJdbcTemplate</classname> and
      <classname>SimpleJdbcTemplate</classname> takes the latter approach.
      When you pass in the values you should pass them in as a
      <classname>java.util.List</classname> of primitive objects. This list
      will be used to insert the required place holders and pass in the values
      during the statement execution.</para>

      <note>
        <para>You need to be careful when passing in a large number of values.
        The JDBC standard doesn't guarantee that you can use more than 100
        values for an IN expression list. Various databases exceed this
        number, but they usually have a hard limit for how many values are
        allowed. Oracle's limit for instance is 1000.</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
      would support a case where there are multiple expressions defined for
      the IN clause like "select * from T_ACTOR where (id, last_name) in ((1,
      'Johnson'), (2, 'Harrop'))". This of course requires that your database
      supports this syntax.</para>
    </section>

    <section id="jdbc-complex-types">
      <title>Handling complex types for stored procedure calls</title>

      <para>When calling stored procedures it's sometimes possible to 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 STRUCT
      object of the user declared type "ITEM_TYPE". 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>

2567 2568 2569 2570
      <para><programlisting language="java"><![CDATA[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",
2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
    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;
      }
2582
    }));]]></programlisting>Going from Java to the database and passing in the
2583 2584 2585 2586 2587 2588 2589 2590
      value of a <classname>TestItem</classname> into a stored procedure is
      done using the <classname>SqlTypeValue</classname>. The
      <classname>SqlTypeValue</classname> interface has a single method named
      "<classname>createTypeValue</classname>" that must be implemented. The
      active connection is passed in and can be used to create database
      specific objects like <classname>StructDescriptor</classname>s or
      <classname>ArrayDescriptor</classname>s</para>

2591 2592 2593 2594
      <para><programlisting language="java"><![CDATA[final TestItem - new TestItem(123L, "A test item", 
        new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"););

SqlTypeValue value = new AbstractSqlTypeValue() {
2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
  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;
  }
2605 2606 2607
};]]></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>
2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624

      <para>Another use for the <classname>SqlTypeValue</classname> is for
      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 we can use the <classname>SqlTypeValue</classname> to
      create an instance of the Oracle <classname>ARRAY</classname> and
      populate it with values from our Java array.</para>

      <programlisting language="java"><![CDATA[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>
2625 2626
    </section>
  </section>
2627

K
Keith Donald 已提交
2628
  <section id="jdbc-embedded-database-support">
2629 2630 2631 2632
    <title>Embedded database support</title>

    <para>The <literal>org.springframework.jdbc.datasource.embedded</literal>
    package provides support for embedded Java database engines. Support for
K
Keith Donald 已提交
2633 2634
    <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. There is
2635 2636 2637 2638
    also an extensible API for plugging in new embedded database types and
    <classname>DataSource</classname> implementations.</para>

    <section id="jdbc-why-embedded-database">
2639
      <title>Why use an embedded database?</title>
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652

      <para>An embedded database is useful during the development phase of a
      project due to its lightweight nature. Ease of configuration, quick
      startup time, testability, and the ability to rapidly evolve SQL during
      development are just some of the benefits of using an embedded
      database.</para>
    </section>

    <section id="jdbc-embedded-database-xml">
      <title>Creating an embedded database instance using Spring XML</title>

      <para>When you wish to expose an embedded database instance as a bean in
      a Spring ApplicationContext, use the embedded-database tag in the
2653
      spring-jdbc namespace: <programlisting language="xml"><![CDATA[    <jdbc:embedded-database id="dataSource">
K
Keith Donald 已提交
2654 2655
        <jdbc:script location="classpath:schema.sql"/>
        <jdbc:script location="classpath:test-data.sql"/>
2656
    </jdbc:embedded-database>
2657
]]></programlisting></para>
2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673

      <para>The configuration above 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 programatically</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:
2674
      <programlisting language="java"><![CDATA[    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
K
Keith Donald 已提交
2675 2676
    EmbeddedDatabase db = builder.type(H2).script("schema.sql").script("test-data.sql").build();
    // do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
2677
    db.shutdown()
2678
]]></programlisting></para>
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
    </section>

    <section id="jdbc-embedded-database-extension">
      <title>Extending the embedded database support</title>

      <para>Spring Jdbc's 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>
K
Keith Donald 已提交
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756
    <section id="jdbc-embedded-database-using-HSQL">
    	<title>Using HSQL</title>
    	<para>
    		Support for HSQL 1.0.0 to 2.0.0 is provided.
    		HSQL is the default database embedded database that will be used if no type is specified explicitly.
    		To specify HSQL explicitly, set the <literal>type</literal> attribute of the <literal>embedded-database</literal> tag to <literal>HSQL</literal>.
    		If using the builder API, call the <literal>type(EmbeddedDatabaseType)</literal> method with <literal>EmbeddedDatabaseType.HSQL</literal>.
    	</para>
    </section>
    <section id="jdbc-embedded-database-using-H2">
    	<title>Using H2</title>
    	<para>
    		Support for H2 1.8.0 to 2.0.0 is provided.
    		To enable H2, set the <literal>type</literal> attribute of the <literal>embedded-database</literal> tag to <literal>H2</literal>.
    		If using the builder API, call the <literal>type(EmbeddedDatabaseType)</literal> method with <literal>EmbeddedDatabaseType.H2</literal>.
    	</para>
    </section>
    <section id="jdbc-embedded-database-using-Derby">
    	<title>Using Derby</title>
    	<para>
    		Support for Apache Derby 10.5.1.1 to 10.6.0 is provided.
    		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>type(EmbeddedDatabaseType)</literal> method with <literal>EmbeddedDatabaseType.Derby</literal>.
    	</para>
    </section>
    <section id="jdbc-embedded-database-dao-testing">
    	<title>Unit testing data access logic with an EmbeddedDatabase</title>
    	<para>
    		Embedded databases provide a lightweight way to test data access code.
    		A basic data access unit test template that uses an embedded database is provided below:
    	</para>
      <programlisting language="java"><![CDATA[
public class DataAccessUnitTestTemplate {
    private EmbeddedDatabase db;
    
    @Before
    public void setUp() {
        // creates a HSQL in-memory db populated from classpath:schema.sql and classpath:test-data.sql
        db = EmbeddedDatabaseBuilder.buildDefault();		
    }
	
    @Test
    public void testDataAccess() {
        JdbcTemplate template = new JdbcTemplate(db);
        template.query(...);
    }
	
    @After
    public void tearDown() {
        db.shutdown();
    }
}
]]></programlisting>    	
    </section>
K
Keith Donald 已提交
2757
  </section>
2758
</chapter>