Spring源码之使用JDBC访问数据 Data access with JDBC

19.1 Introduction to Spring Framework JDBC

Spring Framework JDBC抽象提供的增值功能可能最好由下表中列出的一系列操作来显示。该表显示了Spring将处理哪些操作,以及哪些操作是应用程序开发人员的职责。

Table 19.1. Spring JDBC - who does what?

Action Spring You

Define connection parameters.(定义连接参数。)

 

X

Open the connection.(打开连接)

X

 

Specify the SQL statement.(指定SQL语句。)

 

X

Declare parameters and provide parameter values(声明参数并提供参数值)

 

X

Prepare and execute the statement.(准备并执行语句。)

X

 

Set up the loop to iterate through the results (if any).(设置循环来迭代结果(如果有的话)。)

X

 

Do the work for each iteration.(为每个迭代执行工作。)

 

X

Process any exception.(处理任何异常。)

X

 

Handle transactions.(处理事物)

X

 

Close the connection, statement and resultset.(关闭连接、语句和resultset。)

X

 

 

Spring框架处理了所有底层细节,这些细节使JDBC成为一个乏味的API。

19.1.1 Choosing an approach for JDBC database access 选择JDBC数据库访问方法

您可以选择几种方法来形成JDBC数据库访问的基础。除了JdbcTemplate的三种风格之外,一种新的SimpleJdbcInsert和SimplejdbcCall方法优化了数据库元数据,RDBMS对象样式采用了一种更面向对象的方法,类似于JDO查询设计。一旦您开始使用这些方法中的一种,您仍然可以混合和匹配以包含来自不同方法的特性。所有方法都需要兼容JDBC 2.0的驱动程序,一些高级特性需要JDBC 3.0驱动程序。

  • JdbcTemplate是经典的Spring JDBC方法,也是最流行的。这种“最低级别”的方法和其他所有方法都在幕后使用JdbcTemplate。
  • NamedParameterJdbcTemplate包装了一个JdbcTemplate来提供命名参数,而不是传统的JDBC“?”占位符。当SQL语句有多个参数时,这种方法提供了更好的文档和易用性。
  • SimpleJdbcInsert和SimpleJdbcCall优化数据库元数据,以限制必要的配置数量。这种方法简化了编码,因此您只需要提供表或过程的名称,并提供与列名匹配的参数映射。这只有在数据库提供足够的元数据时才有效。如果数据库不提供此元数据,则必须提供参数的显式配置。
  • RDBMS对象包括MappingSqlQuery、SqlUpdate和StoredProcedure,它们要求您在初始化数据访问层时创建可重用和线程安全的对象。这种方法是在JDO查询之后建模的,在JDO查询中定义查询字符串、声明参数和编译查询。这样做之后,可以多次调用execute方法,并传入各种参数值。

19.1.2 Package hierarchy 包的层次结构

 Spring框架的JDBC抽象框架由四个不同的包组成,即core, datasource, object, and support。

 org.springframework.jdbc.core包含JdbcTemplate类及其各种回调接口,以及各种相关类。

子包org.springframework.jdbc.core.simple包含SimpleJdbcInsert和SimpleJdbcCall类。

另一个名为org.springframework.jdbc.core.namedparam的子包包含NamedParameterJdbcTemplate类和相关的支持类。

org.springframework.jdbc.datasource包包含一个实用程序类,用于方便地访问数据源,以及各种简单的数据源实现,这些实现可用于在Java EE容器之外测试和运行未经修改的JDBC代码。

名为org.springfamework.jdbc.datasource.embedded的子包提供嵌入式支持使用Java数据库引擎(如HSQL、H2和Derby)创建嵌入式数据库。

org.springframework.jdbc.object包包含一些类,它们将RDBMS查询、更新和存储过程表示为线程安全的、可重用的对象。这种方法由JDO建模,尽管查询返回的对象自然与数据库断开连接。这种更高层次的JDBC抽象依赖于org.springframework.jdbc.core包中的低层抽象。

org.springframework.jdbc.support包提供了SQLException翻译功能和一些实用程序类。JDBC处理过程中抛出的异常被转换为org.springframework.dao包中定义的异常。这意味着使用Spring JDBC抽象层的代码不需要实现JDBC或特定于rdbms的错误处理。所有已翻译的异常都是未检查的,这使您可以选择捕获可以从中恢复的异常,同时允许将其他异常传播到调用方。

19.2 Using the JDBC core classes to control basic JDBC processing and error handling 使用JDBC核心类来控制基本的JDBC处理和错误处理

19.2.1 JdbcTemplate

JdbcTemplate类是JDBC核心包中的中心类。它处理资源的创建和释放,帮助您避免常见错误,例如忘记关闭连接。它执行核心JDBC工作流的基本任务,如语句创建和执行,留下应用程序代码来提供SQL和提取结果。JdbcTemplate类执行SQL查询、更新语句和存储过程调用,执行结果集的迭代和返回参数值的提取。它还捕获JDBC异常并将其转换为org.springframework.dao包中定义的通用的、更有信息的异常层次结构。

当您在代码中使用JdbcTemplate时,您只需要实现回调接口,为它们提供一个明确定义的契约。PreparedStatementCreator回调接口为这个类提供的Connection 创建一个准备好的语句,提供SQL和任何必要的参数。对于创建可调用语句的CallableStatementCreator接口也是如此。RowCallbackHandler接口从结果集的每一行提取值。

JdbcTemplate可以在DAO实现中使用,可以通过直接实例化DataSource 引用,也可以在Spring IoC容器中配置,并作为bean引用提供给DAOs。

DataSource 应该始终配置为Spring IoC容器中的bean。在第一种情况下,bean是直接提供给服务的;在第二种情况下,它提供给准备好的模板。

这个类发出的所有SQL都在DEBUG级别的类别下进行日志记录,该类别对应于模板实例的完全限定类名(通常是JdbcTemplate,但如果使用JdbcTemplate类的自定义子类,则可能有所不同)。

Examples of JdbcTemplate class usage JdbcTemplate类使用示例

本节提供了一些使用JdbcTemplate类的示例。这些示例并不是JdbcTemplate公开的所有功能的详尽列表;有关这一点,请参见附带的javadoc。

Querying (SELECT)

下面是一个简单的查询,用于获取关系中的行数:

int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);

一个使用绑定变量的简单查询:

int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
        "select count(*) from t_actor where first_name = ?", Integer.class, "Joe");

查询字符串:

String lastName = this.jdbcTemplate.queryForObject(
        "select last_name from t_actor where id = ?",
        new Object[]{1212L}, String.class);

查询和填充单个域对象:

Actor actor = this.jdbcTemplate.queryForObject(
        "select first_name, last_name from t_actor where id = ?",
        new Object[]{1212L},
        new RowMapper<Actor>() {
            public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
                Actor actor = new Actor();
                actor.setFirstName(rs.getString("first_name"));
                actor.setLastName(rs.getString("last_name"));
                return actor;
            }
        });

查询和填充多个域对象:

List<Actor> actors = this.jdbcTemplate.query(
        "select first_name, last_name from t_actor",
        new RowMapper<Actor>() {
            public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
                Actor actor = new Actor();
                actor.setFirstName(rs.getString("first_name"));
                actor.setLastName(rs.getString("last_name"));
                return actor;
            }
        });

如果最后两个片段代码实际上存在于相同的应用程序,它将意义删除重复出现在两个RowMapper匿名内部类,并提取出来到一个类(通常是一个静态嵌套类),然后可以引用的DAO方法。例如,最好按照以下方式编写最后一个代码片段:

public List<Actor> findAllActors() {
    return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper());
}

private static final class ActorMapper implements RowMapper<Actor> {

    public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
        Actor actor = new Actor();
        actor.setFirstName(rs.getString("first_name"));
        actor.setLastName(rs.getString("last_name"));
        return actor;
    }
}

Updating (INSERT/UPDATE/DELETE) with JdbcTemplate

使用update(..)方法执行插入、更新和删除操作。参数值通常以var args或对象数组的形式提供。

this.jdbcTemplate.update(
        "insert into t_actor (first_name, last_name) values (?, ?)",
        "Leonor", "Watling");
this.jdbcTemplate.update(
        "update t_actor set last_name = ? where id = ?",
        "Banjo", 5276L);
this.jdbcTemplate.update(
        "delete from actor where id = ?",
        Long.valueOf(actorId));

Other JdbcTemplate operations

您可以使用execute(..)方法来执行任意SQL,因此该方法通常用于DDL语句。它被使用回调接口、绑定变量数组等的变量重载了。

this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");

下面的示例调用一个简单的存储过程。稍后将介绍更复杂的存储过程支持。

this.jdbcTemplate.update(
        "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
        Long.valueOf(unionId));

JdbcTemplate best practices JdbcTemplate最佳实践

JdbcTemplate类的实例在配置之后是线程安全的。这很重要,因为这意味着您可以配置JdbcTemplate的一个实例,然后安全地将这个共享引用注入多个DAOs(或存储库)。JdbcTemplate是有状态的,因为它维护对数据源的引用,但是这种状态不是会话状态。

在使用JdbcTemplate类(以及相关的NamedParameterJdbcTemplate类)时,一个常见的做法是在Spring配置文件中配置数据源,然后将共享数据源bean注入到DAO类中;JdbcTemplate是在数据源的setter中创建的。这导致DAOs在某种程度上看起来像下面这样:

public class JdbcCorporateEventDao implements CorporateEventDao {

    private JdbcTemplate jdbcTemplate;

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

    // JDBC-backed implementations of the methods on the CorporateEventDao follow...
}

相应的配置可能是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<beans 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值