`

JdbcTemplate类

阅读更多

11.2. 利用JDBC核心类实现JDBC的基本操作和错误处理
11.2.1. JdbcTemplate类

JdbcTemplate是core包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。

使用JdbcTemplate进行编码只需要根据明确定义的一组契约来实现回调接口。PreparedStatementCreator回调接口通过给定的Connection创建一个PreparedStatement,包含SQL和任何相关的参数。CallableStatementCreateor实现同样的处理,只不过它创建的是CallableStatement。RowCallbackHandler接口则从数据集的每一行中提取值。

我们可以在一个service实现类中通过传递一个DataSource引用来完成JdbcTemplate的实例化,也可以在application context中配置一个JdbcTemplate bean,来供service使用。需要注意的是DataSource在application context总是配制成一个bean,第一种情况下,DataSource bean将传递给service,第二种情况下DataSource bean传递给JdbcTemplate bean。因为JdbcTemplate使用回调接口和SQLExceptionTranslator接口作为参数,所以一般情况下没有必要通过继承JdbcTemplate来定义其子类。

JdbcTemplate中使用的所有SQL将会以“DEBUG”级别记入日志(一般情况下日志的category是JdbcTemplate相应的全限定类名,不过如果需要对JdbcTemplate进行定制的话,可能是它的子类名)。
11.2.2. NamedParameterJdbcTemplate类

NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用'?'占位符来表示的。 NamedParameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,并作为其代理来完成大部分工作。下面的内容主要针对NamedParameterJdbcTemplate与JdbcTemplate的不同之处来加以说明,即如何在SQL语句中使用命名参数。

通过下面的例子我们可以更好地了解NamedParameterJdbcTemplate的使用模式(在后面我们还有更好的使用方式)。
// some JDBC-backed DAO class...
public int countOfActorsByFirstName(String firstName) {

    String sql = "select count(0) from T_ACTOR where first_name = :first_name";

    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);

    return template.queryForInt(sql, namedParameters);
}

在上面例子中,sql变量使用了命名参数占位符“first_name”,与其对应的值存在namedParameters变量中(类型为MapSqlParameterSource)。

如果你喜欢的话,也可以使用基于Map风格的名值对将命名参数传递给NamedParameterJdbcTemplate(NamedParameterJdbcTemplate实现了NamedParameterJdbcOperations接口,剩下的工作将由调用该接口的相应方法来完成,这里我们就不再赘述):
// some JDBC-backed DAO class...
public int countOfActorsByFirstName(String firstName) {

    String sql = "select count(0) from T_ACTOR where first_name = :first_name";

    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    Map namedParameters = new HashMap();
    namedParameters.put("first_name", firstName);

    return template.queryForInt(sql, namedParameters);
}

另外一个值得一提的特性是与NamedParameterJdbcTemplate位于同一个包中的SqlParameterSource接口。在前面的代码片断中我们已经看到了该接口的实现(即MapSqlParameterSource类),SqlParameterSource可以用来作为NamedParameterJdbcTemplate命名参数的来源。MapSqlParameterSource类是一个非常简单的实现,它仅仅是一个java.util.Map适配器,当然其用法也就不言自明了(如果还有不明了的,可以在Spring的JIRA系统中要求提供更多的相关资料)。

SqlParameterSource接口的另一个实现--BeanPropertySqlParameterSource为我们提供了更有趣的功能。该类包装一个类似JavaBean的对象,所需要的命名参数值将由包装对象提供,下面我们使用一个例子来更清楚地说明它的用法。
// some JavaBean-like class...
public class Actor {

    private Long id;
    private String firstName;
    private String lastName;
   
    public String getFirstName() {
        return this.firstName;
    }
   
    public String getLastName() {
        return this.lastName;
    }
   
    public Long getId() {
        return this.id;
    }
   
    // setters omitted...

}
// some JDBC-backed DAO class...
public int countOfActors(Actor exampleActor) {

 // notice how the named parameters match the properties of the above 'Actor' class
    String sql = "select count(0) from T_ACTOR where first_name = :firstName and last_name = :lastName";

    NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());
    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);

    return template.queryForInt(sql, namedParameters);
}

大家必须牢记一点:NamedParameterJdbcTemplate类内部包装了一个标准的JdbcTemplate类。如果你需要访问其内部的JdbcTemplate实例(比如访问JdbcTemplate的一些方法)那么你需要使用getJdbcOperations()方法返回的JdbcOperations接口。(JdbcTemplate实现了JdbcOperations接口)。

NamedParameterJdbcTemplate类是线程安全的,该类的最佳使用方式不是每次操作的时候实例化一个新的NamedParameterJdbcTemplate,而是针对每个DataSource只配置一个NamedParameterJdbcTemplate实例(比如在Spring IoC容器中使用Spring IoC来进行配置),然后在那些使用该类的DAO中共享该实例。
11.2.3. SimpleJdbcTemplate类
注意

请注意该类所提供的功能仅适用于Java 5 (Tiger)。

SimpleJdbcTemplate类是JdbcTemplate类的一个包装器(wrapper),它利用了Java 5的一些语言特性,比如Varargs和Autoboxing。对那些用惯了Java 5的程序员,这些新的语言特性还是很好用的。

SimpleJdbcTemplate 类利用Java 5的语法特性带来的好处可以通过一个例子来说明。在下面的代码片断中我们首先使用标准的JdbcTemplate进行数据访问,接下来使用SimpleJdbcTemplate做同样的事情。
// classic JdbcTemplate-style...
public Actor findActor(long id) {
    String sql = "select id, first_name, last_name from T_ACTOR where id = ?";
   
    RowMapper mapper = new RowMapper() {
   
        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            Actor actor = new Actor();
            actor.setId(rs.getLong(Long.valueOf(rs.getLong("id"))));
            actor.setFirstName(rs.getString("first_name"));
            actor.setLastName(rs.getString("last_name"));
            return actor;
        }
    };
   
    // normally this would be dependency injected of course...
    JdbcTemplate jdbcTemplate = new JdbcTemplate(this.getDataSource());
   
    // notice the cast, and the wrapping up of the 'id' argument
    // in an array, and the boxing of the 'id' argument as a reference type
    return (Actor) jdbcTemplate.queryForObject(sql, mapper, new Object[] {Long.valueOf(id)});
}

下面是同一方法的另一种实现,惟一不同之处是我们使用了SimpleJdbcTemplate,这样代码显得更加清晰。
// SimpleJdbcTemplate-style...
public Actor findActor(long id) {
    String sql = "select id, first_name, last_name from T_ACTOR where id = ?";

    ParameterizedRowMapper<Actor> mapper = new ParameterizedRowMapper<Actor>() {
   
        // notice the return type with respect to Java 5 covariant return types
        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;
        }
    };

    // again, normally this would be dependency injected of course...
    SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(this.getDataSource());

    return simpleJdbcTemplate.queryForObject(sql, mapper, id);
}
11.2.4. DataSource接口

为了从数据库中取得数据,我们首先需要获取一个数据库连接。 Spring通过DataSource对象来完成这个工作。 DataSource是JDBC规范的一部分, 它被视为一个通用的数据库连接工厂。通过使用DataSource, Container或Framework可以将连接池以及事务管理的细节从应用代码中分离出来。 作为一个开发人员,在开发和测试产品的过程中,你可能需要知道连接数据库的细节。 但在产品实施时,你不需要知道这些细节。通常数据库管理员会帮你设置好数据源。

在使用Spring JDBC时,你既可以通过JNDI获得数据源,也可以自行配置数据源( 使用Spring提供的DataSource实现类)。使用后者可以更方便的脱离Web容器来进行单元测试。 这里我们将使用DriverManagerDataSource,不过DataSource有多种实现, 后面我们会讲到。使用DriverManagerDataSource和你以前获取一个JDBC连接 的做法没什么两样。你首先必须指定JDBC驱动程序的全限定名,这样DriverManager 才能加载JDBC驱动类,接着你必须提供一个url(因JDBC驱动而异,为了保证设置正确请参考相关JDBC驱动的文档), 最后你必须提供一个用户连接数据库的用户名和密码。下面我们将通过一个例子来说明如何配置一个 DriverManagerDataSource:
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername("sa");
dataSource.setPassword("");
11.2.5. SQLExceptionTranslator接口

SQLExceptionTranslator是一个接口,如果你需要在 SQLException和org.springframework.dao.DataAccessException之间作转换,那么必须实现该接口。

转换器类的实现可以采用一般通用的做法(比如使用JDBC的SQLState code),如果为了使转换更准确,也可以进行定制(比如使用Oracle的error code)。

SQLErrorCodeSQLExceptionTranslator是SQLExceptionTranslator的默认实现。 该实现使用指定数据库厂商的error code,比采用SQLState更精确。 转换过程基于一个JavaBean(类型为SQLErrorCodes)中的error code。 这个JavaBean由SQLErrorCodesFactory工厂类创建,其中的内容来自于 "sql-error-codes.xml"配置文件。该文件中的数据库厂商代码基于Database MetaData信息中的 DatabaseProductName,从而配合当前数据库的使用。


SQLErrorCodeSQLExceptionTranslator使用以下的匹配规则:


首先检查是否存在完成定制转换的子类实现。通常SQLErrorCodeSQLExceptionTranslator 这个类可以作为一个具体类使用,不需要进行定制,那么这个规则将不适用。

接着将SQLException的error code与错误代码集中的error code进行匹配。 默认情况下错误代码集将从SQLErrorCodesFactory取得。 错误代码集来自classpath下的sql-error-codes.xml文件, 它们将与数据库metadata信息中的database name进行映射。

如果仍然无法匹配,最后将调用fallbackTranslator属性的translate方法,SQLStateSQLExceptionTranslator类实例是默认的fallbackTranslator。


SQLErrorCodeSQLExceptionTranslator可以采用下面的方式进行扩展:
public class MySQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
    protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) {
        if (sqlex.getErrorCode() == -12345) {
            return new DeadlockLoserDataAccessException(task, sqlex);
        }
        return null;
    }
}

在上面的这个例子中,error code为'-12345'的SQLException 将采用该转换器进行转换,而其他的error code将由默认的转换器进行转换。 为了使用该转换器,必须将其作为参数传递给JdbcTemplate类 的setExceptionTranslator方法,并在需要使用这个转换器器的数据 存取操作中使用该JdbcTemplate。 下面的例子演示了如何使用该定制转换器:
// create a JdbcTemplate and set data source
JdbcTemplate jt = new JdbcTemplate();
jt.setDataSource(dataSource);
// create a custom translator and set the DataSource for the default translation lookup
MySQLErrorCodesTransalator tr = new MySQLErrorCodesTransalator();
tr.setDataSource(dataSource);
jt.setExceptionTranslator(tr);
// use the JdbcTemplate for this SqlUpdate
SqlUpdate su = new SqlUpdate();
su.setJdbcTemplate(jt);
su.setSql("update orders set shipping_charge = shipping_charge * 1.05");
su.compile();
su.update();

在上面的定制转换器中,我们给它注入了一个数据源,因为我们仍然需要 使用默认的转换器从sql-error-codes.xml中获取错误代码集。
11.2.6. 执行SQL语句

我们仅需要非常少的代码就可以达到执行SQL语句的目的,一旦获得一个 DataSource和一个JdbcTemplate, 我们就可以使用JdbcTemplate提供的丰富功能实现我们的操作。 下面的例子使用了极少的代码完成创建一张表的工作。
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

public class ExecuteAStatement {

    private JdbcTemplate jt;
    private DataSource dataSource;

    public void doExecute() {
        jt = new JdbcTemplate(dataSource);
        jt.execute("create table mytable (id integer, name varchar(100))");
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}
11.2.7. 执行查询

除了execute方法之外,JdbcTemplate还提供了大量的查询方法。 在这些查询方法中,有很大一部分是用来查询单值的。比如返回一个汇总(count)结果 或者从返回行结果中取得指定列的值。这时我们可以使用queryForInt(..)、 queryForLong(..)或者queryForObject(..)方法。 queryForObject方法用来将返回的JDBC类型对象转换成指定的Java对象,如果类型转换失败将抛出 InvalidDataAccessApiUsageException异常。 下面的例子演示了两个查询的用法,一个返回int值,另一个返回 String。
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

public class RunAQuery {

    private JdbcTemplate jt;
    private DataSource dataSource;
 
    public int getCount() {
        jt = new JdbcTemplate(dataSource);
        int count = jt.queryForInt("select count(*) from mytable");
        return count;
    }

    public String getName() {
        jt = new JdbcTemplate(dataSource);
        String name = (String) jt.queryForObject("select name from mytable", String.class);
        return name;
    }

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

除了返回单值的查询方法,JdbcTemplate还提供了一组返回List结果 的方法。List中的每一项对应查询返回结果中的一行。其中最简单的是queryForList方法, 该方法将返回一个List,该List中的每一条 记录是一个Map对象,对应应数据库中某一行;而该Map 中的每一项对应该数据库行中的某一列值。下面的代码片断接着上面的例子演示了如何用该方法返回表中 所有记录:
public List getList() {
    jt = new JdbcTemplate(dataSource);
    List rows = jt.queryForList("select * from mytable");
    return rows;
}

返回的结果集类似下面这种形式:
[{name=Bob, id=1}, {name=Mary, id=2}]
11.2.8. 更新数据库

JdbcTemplate还提供了一些更新数据库的方法。 在下面的例子中,我们根据给定的主键值对指定的列进行更新。 例子中的SQL语句中使用了“?”占位符来接受参数(这种做法在更新和查询SQL语句中很常见)。 传递的参数值位于一个对象数组中(基本类型需要被包装成其对应的对象类型)。
import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

public class ExecuteAnUpdate {

    private JdbcTemplate jt;
    private DataSource dataSource;

    public void setName(int id, String name) {
        jt = new JdbcTemplate(dataSource);
        jt.update("update mytable set name = ? where id = ?", new Object[] {name, new Integer(id)});
    }

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

分享到:
评论
1 楼 hzxlb910 2013-06-26  
代码重新整理一下就好了

相关推荐

    Spring框架JdbcTemplate类中查询方法介绍

    Spring 框架 JdbcTemplate 类中查询方法介绍 JdbcTemplate 是 Spring 框架中 org.springframework.jdbc.core 包提供的 JDBC 模板类,它是核心类,其他模板类都是基于它封装完成的。JdbcTemplate 类主要提供四类方法...

    Spring JdbcTemplate 常用方法整理

    Spring的JdbcTemplate是Spring框架中用于简化数据库操作的工具类,它是基于JDBC但又抽象出了一层,避免了直接与数据库驱动API交互,从而提高了代码的可读性和可维护性。本文将深入探讨Spring JdbcTemplate的常用方法...

    spring-jdbcTemplate实例工程

    《深入解析Spring JdbcTemplate》 Spring JDBC Template是Spring框架中用于简化JDBC操作的一个核心组件,它是Spring对JDBC API的封装,旨在提供一个更加简洁、健壮且可测试的数据库访问层。在这个实例工程中,我们...

    JdbcTemplate

    Spring框架为简化这一过程提供了JdbcTemplate类,它基于Java Database Connectivity (JDBC) API,但通过一系列抽象和自动处理,使得数据库操作更加安全、易用且易于测试。JdbcTemplate是Spring JDBC模块的核心组件,...

    SpringJdbcTemplate封装工具类

    SpringJdbcTemplate是一个模板类,它提供了大量的方法来执行SQL查询、更新、存储过程等操作。这些方法会自动处理JDBC相关的资源关闭、异常转换等细节,使得代码更加整洁和健壮。 2. **数据库自适应** Spring...

    jdbcTemplate相关jar包.zip

    spring-jdbc.jar包含了Spring对JDBC的抽象层,包括JdbcTemplate类和SimpleJdbcInsert、SimpleJdbcCall等工具类。JdbcTemplate提供了一套模板化的API,用于执行SQL查询、更新、存储过程等操作,同时自动处理结果集、...

    jdbcTemplate需要用到的jar包.zip

    这个文件提供了JdbcTemplate类和其他相关支持类。 2. **JDBC驱动**:根据你使用的数据库类型,你需要相应的JDBC驱动。例如,如果你使用的是MySQL,你需要`mysql-connector-java.jar`;如果是Oracle,则需要`ojdbc....

    java jdbcTemplate

    commons-logging-1.2.jar spring-jdbc-5.1.10.RELEASE.jar spring-core-5.1.10.RELEASE.jar spring-beans-5.1.10.RELEASE.jar ...

    spring5JdbcTemplate需要的jar

    1. `spring-jdbc.jar`:这是Spring JDBC模块的核心库,包含了JdbcTemplate类和其他相关的接口和类。这个jar包提供了对JDBC操作的封装,使得你可以方便地执行SQL语句并处理结果。 2. `spring-tx.jar`:Spring的事务...

    Spring JdbcTemplate方法详解

    JdbcTemplate主要提供以下五类方法;JdbcTemplate类支持的回调类;并附例子

    在项目中导入.rar

    在这个名为“在项目中导入.rar”的压缩包里,包含了几个关键的Java库,它们是JDBC连接池和JDBCTemplate类的jar包。这些组件能够极大地提升数据库操作的性能,减少资源消耗,并优化用户访问体验。 首先,让我们了解...

    JdbcTemplate完全学习

    JdbcTemplate类通过模板设计模式帮助我们消除了冗长的代码,只做需要做的事情(即可变部分),并且帮我们做哪些固定部分,如连接的创建及关闭。JdbcTemplate类对可变部分采用回调接口方式实现,如ConnectionCallback...

    jdbcTemplate分页彻底解决,使用游标滚动

    `JdbcTemplateExtend.java`可能扩展了`JdbcTemplate`类,添加了对游标分页的支持。它可能包含了一个或多个方法,用于封装上述步骤,使代码更加简洁易用。 在实际应用中,我们可能还需要考虑并发和性能优化,例如,...

    Spring--JdbcTemplate.pdf

    4. 在DAO类中注入JdbcTemplate对象,这通常是通过Spring的依赖注入特性完成的。 5. 创建与数据库表对应的实体类,用于在Java代码中表示表中的数据。 6. 编写Service和DAO类中实现具体数据库操作的方法,如添加、删除...

    JDBC Template源码.7z

    在源码中,可以看到JdbcTemplate类如何组织这些操作,如`execute()`、`queryForList()`、`update()`等方法。 `PropertyPlaceholderConfigurer`是Spring框架中的一个bean,用于处理属性占位符,如`${property}`。它...

    JdbcTemplate的事务控制.docx

    使用Spring的声明式事务管理,我们可以在Bean的类或方法上添加`@Transactional`注解,例如: ```java @Service public class UserService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional ...

    jdbcTemplate

    在`jdbcTemplate`压缩包文件中,可能包含了实现上述功能的类、配置文件以及其他辅助工具类。这些文件可以帮助我们理解项目中如何自定义和使用`JDBCTemplate`。通过查看这些源码,我们可以学习到如何在实际项目中优化...

    JdbcTemplate通用泛型Dao实现

    通过定义一个泛型接口,我们可以创建一个通用的数据访问对象(DAO),这个DAO可以处理任何类型的实体类,只要它们遵循一定的规则,比如拥有ID字段。这样,我们就只需要编写一次DAO的实现,就可以为不同的数据表提供...

Global site tag (gtag.js) - Google Analytics