SimpleJdbcTemplate:Spring 2.0 和 Java 5

工程 | Ben Hale | 2006 年 11 月 28 日 | ...

The Spring Experience 大会临近之际,我一直很忙,但我注意到 Rod 在博客方面非常活跃。所以今天在机场和飞机上的一些空闲时间里,我决定写一点博客。

我们在 Spring 社区面临的最大挑战之一是既要保持向后兼容,又要持续创新。创新的一部分是利用 Java 5 及更高版本的新特性和构造。自 1.2.x 分支以来,我们已经看到了一些这方面的例子,例如 `@Transactional` 注解以及基于 `@ManagedResource` 注解的 JMX 自动检测。最终,这些都是很棒的特性,极大地简化了开发(至少对我而言),但它们实际上是将元数据移到了代码中。我们还没有看到 API 的实际简化。

Spring 2.0 改变了这一点。我们看到某些 API 利用的不仅仅是注解。事实上,有一个很好的例子,其中几乎所有 Java 5 的新语言特性(自动装箱、可变参数、泛型)都被使用了,那就是 `SimpleJdbcTemplate`。`SimpleJdbcTemplate` 并不是标准 `JdbcTemplate` 的替代品,而是利用 Java 5 来简化某些常见任务。

自动装箱

严格来说,自动装箱并不是我们通过 API 来实现的,但它可以让使用 `JdbcTemplate` 更加方便。例如,过去你需要手动装箱你的原始值……

public int getLargeAccountCount(double value, int type) {
    return getSimpleJdbcTemplate().queryForInt(
        "select count(*) from accounts where balance > ? and type = ?",
        new Object[] { new Double(value), new Integer(type) });
}

……现在你不再需要了。


public int getLargeAccountCount(double value, int type) {
    return getSimpleJdbcTemplate().queryForInt(
        "select count(*) from accounts where balance > ? and type = ?",
        new Object[] { value, type });
}

在这个简单的例子中,差异并不大,但你可以想象在一个具有多个绑定变量的复杂 SQL 查询中,装箱会占用相当大的空间。

可变参数

如果我们回顾一下最初的例子,我们会看到 Java 5 可以帮助我们移除另一个样板代码。绑定参数以 `Object` 数组的形式传递,但 Java 5 允许我们只指定一个逗号分隔的对象列表,它会自动转换为所需的 `Object` 数组。

所以,如果我们从最初的例子开始……


public int getLargeAccountCount(double value, int type) {
    return getSimpleJdbcTemplate().queryForInt(
        "select count(*) from accounts where balance > ? and type = ?",
        new Object[] { new Double(value), new Integer(type) });
}

……结合自动装箱和可变参数,代码真的开始变短了。


public int getLargeAccountCount(double value, int type) {
    return getSimpleJdbcTemplate().queryForInt(
        "select count(*) from accounts where balance > ? and type = ?",
        value, type);
}

泛型

我们在 `SimpleJdbcTemplate` 中看到的最后一个改进是引入了泛型。对我来说,使用 `JdbcTemplate` 时最大的痛点之一是,每当我执行 `queryForObject()` 时,我都必须进行手动类型转换,而且我的 IDE 或编译器也帮不上什么忙。

public Account getAccount(long id) {
    return (Account) getJdbcTemplate().queryForObject(
        "select * from accounts where id = ?",
        new Object[] { new Long(id) }, new RowMapper() {

            public Object mapRow(ResultSet rs, int rowNum)
                    throws SQLException {
                String accountNumber = rs.getString("account_number");
                int balance = rs.getInt("balance");
                return new Account(accountNumber, balance);
            }
        });
}

在 Spring 2.0 中,我们发布了 `SimpleJdbcTemplate` 的伴侣 `ParameterizedRowMapper`。当两者一起使用时,它们实际上创建了一个非常漂亮的系统,完全不需要类型转换,并且你的 IDE 和编译器会进行强类型检查。


public Account getAccount(long id) {
    return getSimpleJdbcTemplate().queryForObject(
        "select * from accounts where id = ?",
        new ParameterizedRowMapper<Account>() {

            public Account mapRow(ResultSet rs, int rowNum)
                    throws SQLException {
                String accountNumber = rs.getString("account_number");
                int balance = rs.getInt("balance");
                return new Account(accountNumber, balance);
            }
        }, id);
}

有一点很重要,那就是 `SimpleJdbcTemplate` 并没有包含 `JdbcTemplate` 的所有方法。它甚至不继承 `JdbcTemplate`,而是可以提供一个 `JdbcTemplate` 的引用。`SimpleJdbcTemplate` 的目标是在利用 Java 5 的同时,简化一些常见行为的使用。

总而言之,这并不是什么革命性的东西。就像 Rod 在他早期的帖子中提到的那样,这只是语法糖。但这是 Spring 拥抱 Java 5 及以后新特性的一个例子。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有