`
davidxiaozhi
  • 浏览: 241575 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

利用JDBC核心类控制JDBC的基本操作和错误处理

阅读更多

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接口则从数据集的每一行中提取值。

我们可以在DAO实现类中通过传递一个DataSource引用来完成JdbcTemplate的实例化,也可以在Spring的IoC容器中配置一个JdbcTemplate的bean并赋予DAO实现类作为一个实例。 需要注意的是DataSource在Spring的IoC容器中总是配制成一个bean,第一种情况下,DataSource bean将传递给service,第二种情况下DataSource bean传递给JdbcTemplate bean。

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

11.2.1.1. 一些示例

下面是一些使用JdbcTemplate类的示例。(这些示例并不是完整展示所有的JdbcTemplate所暴露出来的功能。请查看与之相关的Javadoc)。

11.2.1.1.1. 查询(SELECT)

一个简单的例子用于展示如何获取一个表中的所有行数。

int rowCount = this.jdbcTemplate.queryForInt("select count(0) from t_accrual");

一个简单的例子展示如何进行参数绑定。

int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt(
        "select count(0) from t_actors where first_name = ?", new Object[]{"Joe"});

查询一个String

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

查询并将结果记录为一个简单的数据模型。

Actor actor = (Actor) this.jdbcTemplate.queryForObject(
    "select first_name, surname from t_actor where id = ?",
    new Object[]{new Long(1212)},
    new RowMapper() {

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

查询并组装多个数据模型。

Collection actors = this.jdbcTemplate.query(
    "select first_name, surname from t_actor",
    new RowMapper() {

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

如果最后2个示例中的代码出现在同一段程序中,我们有必要去掉这些重复的RowMapper匿名类代码,将这些代码抽取到一个单独的类中(通常是一个静态的内部类)。 这样,这个内部类就可以在DAO的方法中被共享。因而,最后2个示例写成如下的形式将更加好:

public Collection findAllActors() {
    return this.jdbcTemplate.query( "select first_name, surname from t_actor", new ActorMapper());
}

private static final class ActorMapper implements RowMapper {

    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        Actor actor = new Actor();
        actor.setFirstName(rs.getString("first_name"));
        actor.setSurname(rs.getString("surname"));
        return actor;
    }
}
11.2.1.1.2. 更新(INSERT/UPDATE/DELETE)
this.jdbcTemplate.update(
        "insert into t_actor (first_name, surname) values (?, ?)", 
        new Object[] {"Leonor", "Watling"});
this.jdbcTemplate.update(
        "update t_actor set weapon = ? where id = ?", 
        new Object[] {"Banjo", new Long(5276)});
this.jdbcTemplate.update(
        "delete from actor where id = ?",
        new Object[] {new Long.valueOf(actorId)});
11.2.1.1.3. 其他操作

execute(..)方法可以被用作执行任何类型的SQL,甚至是DDL语句。 这个方法的实现需要传入一个回调接口、需要绑定的参数数组等作为参数。

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

调用一个简单的存储过程(更多复杂的存储过程支持请参见存储过程支持)。

this.jdbcTemplate.update(
        "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", 
        new Object[]{Long.valueOf(unionId)});

11.2.1.2. JdbcTemplate 的最佳实践

JdbcTemplate类的实例是线程安全的实例。这一点非常重要,正因为如此,你可以配置一个简单的JdbcTemplate实例,并将这个“共享的”、“安全的”实例注入到不同的DAO类中去。 另外, JdbcTemplate 是有状态的,因为他所维护的DataSource 实例是有状态的,但是这种状态是无法变化的。

使用JdbcTemplate的一个常见的最佳实践(同时也是SimpleJdbcTemplateNamedParameterJdbcTemplate 类的最佳实践)就是在Spring配置文件中配置一个DataSource实例,然后将这个共享的DataSource实例助于到你的DAO中去。 而JdbcTemplate的实例将在DataSource的setter方法中被创建。这样的话,DAO可能看上去像这样:

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 xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- the DataSource (parameterized for configuration via a PropertyPlaceHolderConfigurer) -->
    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
        <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>

</beans>

如果你使用Spring提供的JdbcDaoSupport类,并且你的那些基于JDBC的DAO都继承自这个类,那么你会自动地从JdbcDaoSupport类中继承了setDataSource(..)方法。 是否将你的DAO类继承自这些类完全取决于你自己的决定,事实上这并不是必须的,如果你看一下JdbcDaoSupport类你会发现,这里只是提供了一个简便的方式而已。

无论你是否使用上述这种初始化方式,都无需在执行某些SQL操作时多次创建一个JdbcTemplate实例。记住,一旦JdbcTemplate被创建,他是一个线程安全的对象。 一个你需要创建多次JdbcTemplate实例的理由可能在于,你的应用需要访问多个不同的数据库,从而需要不同的DataSources来创建不同的JdbcTemplates实例。

11.2.2. NamedParameterJdbcTemplate

NamedParameterJdbcTemplate类为JDBC操作增加了命名参数的特性支持,而不是传统的使用('?')作为参数的占位符。NamedParameterJdbcTemplate类对JdbcTemplate类进行了封装, 在底层,JdbcTemplate完成了多数的工作。这一个章节将主要描述NamedParameterJdbcTemplate类与JdbcTemplate类的一些区别,也就是使用命名参数进行JDBC操作。

// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

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

public int countOfActorsByFirstName(String firstName) {

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

    SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);

    return namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}

注意这里在'sql'中使用了命名参数作为变量,而这个名称所对应的值被定义在传入的'namedParameters' 中作为参数(也可以传入到MapSqlParameterSource中作为参数)。

你也可以传入许多命名参数以及他们所对应的值,以Map的方式,作为键值对传入到NamedParameterJdbcTemplate中。 (其余的被NamedParameterJdbcOperations所暴露的接口以及NamedParameterJdbcTemplate实现类遵循了类似的方式,此处不包含相关内容)。

// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

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

public int countOfActorsByFirstName(String firstName) {

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

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

    return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}

NamedParameterJdbcTemplate类所具备的另外一个比较好的特性就是可以接收SqlParameterSource作为传入参数 (这个类位于相同的包定义中)。 你已经在先前的一个例子中看到了这个接口的一个具体实现类。( MapSqlParameterSource类)。而SqlParameterSource 这个接口对于NamedParameterJdbcTemplate类的操作而言是一个传入的参数。MapSqlParameterSource只是一个非常简单的实现,使用了java.util.Map作为转接器, 其中,Map中的Key表示参数名称,而Map中的Value表示参数值。

另外一个SqlParameterSource 的实现类是BeanPropertySqlParameterSource。这个类对传统的Java进行了封装(也就是那些符合JavaBean标准的类), 并且使用了JavaBean的属性作为参数的名称和值。

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...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

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

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";

    SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);

    return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters);
}

注意,NamedParameterJdbcTemplate类只是封装JdbcTemplate模板; 因而如果你需要访问相应被封装的JdbcTemplate类,并访问一些只有在JdbcTemplate中拥有的功能,你需要使用getJdbcOperations()方法来进行访问。

请参照第 11.2.1.2 节 “JdbcTemplate 的最佳实践”来获取一些使用NamedParameterJdbcTemplate的最佳实践。

11.2.3. SimpleJdbcTemplate

注意

SimpleJdbcTemplate所提供的一些特性必须工作在Java 5及以上版本。

SimpleJdbcTemplate类是对JdbcTemplate类进行的封装,从而可以充分利用Java 5所带来的varargs和autoboxing等特性。 SimpleJdbcTemplate类完全利用了Java 5语法所带来的蜜糖效应。凡是使用过Java 5的程序员们如果要从Java 5迁移回之前的JDK版本,无疑会发现这些特性所带来的蜜糖效应。

“before and after”示例可以成为SimpleJdbcTemplate类所带来的蜜糖效应的最佳诠释。 下面的代码示例首先展示了使用传统的JdbcTemplate进行JDBC访问的代码,接着是使用SimpleJdbcTemplate类做同样的事情。

// classic JdbcTemplate-style...
private JdbcTemplate jdbcTemplate;

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

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("id"));
            actor.setFirstName(rs.getString("first_name"));
            actor.setLastName(rs.getString("last_name"));
            return actor;
        }
    };
    
    // notice the cast, 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...
private SimpleJdbcTemplate simpleJdbcTemplate;

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

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;
        }
    };

    return this.simpleJdbcTemplate.queryForObject(sql, mapper, id);
}

请同样参照第 11.2.1.2 节 “JdbcTemplate 的最佳实践”来获取一些SimpleJdbcTemplate的最佳实践

注意

SimpleJdbcTemplate只是提供了JdbcTemplate所提供的功能的子类。 如果你需要使用JdbcTemplate的方法,而这些方法又没有在SimpleJdbcTemplate中定义,你需要调用getJdbcOperations()方法 获取相应的方法调用。JdbcOperations接口中定义的方法需要在这边做强制转化才能使用。

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是一个接口,如�%9利用JDBC核心类控制JDBC的基本操作和错误处理

分享到:
评论

相关推荐

    JDBC操作技术 PDF

    ### 错误处理和异常 JDBC操作中可能出现的异常主要有`SQLException`及其子类,如`SQLIntegrityConstraintViolationException`、`SQLTimeoutException`等。当出现异常时,需要捕获并处理这些异常,确保程序的健壮性...

    JDBC操作数据库辅助类

    在给定的文件中,我们有四个核心类:JdbcSession、JdbcSessionException、JdbcResourceManager和JdbcSessionFactory。这些类构成了一个完整的JDBC辅助库,提供了一套方便的接口来执行数据库操作。通过分析这些类的源...

    异常处理和JDBC

    综上所述,“异常处理和JDBC”涵盖了Java编程中与数据库交互的核心技术,包括如何优雅地处理可能出现的问题,以及如何利用JDBC提供的强大工具来高效、安全地操作数据库。学习并掌握这些知识点对于任何Java开发者来说...

    struts1利用JDBC实现增删改查

    首先,我们需要了解Struts1的核心组件: 1. **ActionServlet**:Struts1的入口点,负责处理所有的HTTP请求,并根据配置文件(struts-config.xml)将请求分发到相应的Action。 2. **Action**:业务逻辑处理类,实现...

    JDBC与Java数据库编程

    - **JDBC 1.x**:最初版本,提供了基本的数据存储架构和核心接口,如`DriverManager`、`Connection`、`Statement`和`ResultSet`等。 - **JDBC 2.0**:引入了可滚动结果集、可更新结果集、批量更新等功能,增强了性能...

    利用JDBC的图书馆管理系统

    JDBC是Java语言中用于与各种数据库交互的一组接口和类,它提供了标准的方法来连接、查询、更新数据库。在本项目中,我们需要使用JDBC驱动来建立与SQL Server的连接,执行SQL语句,并处理查询结果。确保正确地配置...

    JDBC 4.3规范文档

    它不仅提供了接口的定义,还涉及到数据类型映射、错误处理、连接管理、安全性、国际化和遗留问题的处理等。JDBC规范的API允许Java应用程序能够与各种关系数据库进行交互操作,其核心功能包括创建连接、发送SQL命令、...

    数据库dao操作jdbc

    DAO设计模式的核心思想是创建一个接口或抽象类,代表特定的数据对象,然后实现这个接口或抽象类来处理与数据库的交互。在Java中,通常会为每个数据库表创建一个DAO类,用于执行CRUD(Create、Read、Update、Delete)...

    jdbc参考手册

    JDBC中的SQLException类用于处理在数据库操作过程中可能出现的错误。通过捕获并处理SQLException,可以在数据库操作失败时提供有用的错误信息,从而提高程序的健壮性和用户体验。 在JDBC中,可以将多个SQL语句组合...

    sqljdbc_6.0

    此外,JDBC 6.0版本可能引入了一些新特性,例如增强的性能优化、更好的错误处理机制、支持更多的数据库特性(如XML类型处理、存储过程的调用等)以及对Java 8特性的兼容。开发者在实际应用中应参考官方文档,了解...

    尚硅谷jdbc视频教程

    1. **DriverManager**: 它是JDBC的核心类之一,用于加载JDBC驱动并建立与数据库的连接。 2. **Connection**: 表示与数据库之间的连接,它是所有其他JDBC对象的工厂。 3. **Statement**: 用于向数据库发送静态SQL语句...

    JDBC操作(ppt)

    - JDBC 4.1引入了更好的错误处理,例如SQLException的getCause()方法。 - JDBC 4.2增加了对Java 8日期和时间类型的原生支持。 总之,JDBC是Java编程语言访问数据库的标准,理解并熟练掌握JDBC操作对于任何Java...

    oracle jdbc jar包

    在开发过程中,注意管理和优化JDBC连接,避免资源泄漏,以及确保良好的错误处理机制,都是提高应用稳定性和性能的关键。同时,遵循最佳实践,如使用连接池管理数据库连接,可以有效地提升系统性能和可维护性。

    sqljdbc41.jar

    在信息技术领域,数据库是存储和管理数据的核心组件。SQLServer作为微软公司推出的强大关系型数据库管理系统,广泛应用于企业级应用开发。对于Java开发者而言,与SQLServer进行交互时,就需要使用到数据库驱动。本文...

    sqljdbc_3.0

    1. 主要的JDBC驱动类库(如mssql-jdbc.jar或sqljdbc4.jar),这是连接SQL Server数据库的核心组件。 2. 配置文件,如readme.txt或license.txt,包含了使用驱动的说明和许可信息。 3. 示例代码或文档,演示如何在Java...

    Oracle jdbc 单例 工具类

    - 错误处理:处理异常,如`SQLException`,确保程序的健壮性。 - 连接池:虽然这里提到的是单例,但实际生产环境中,通常使用连接池(如C3P0、HikariCP)来管理和复用数据库连接,以提高性能。 5. **数据库配置**...

    SQL Server Driver for JDBC (JDBC 连接SQL Server 2000 )

    这些类可能用于数据库连接池管理、性能优化、错误处理、日期时间处理等,帮助开发者更高效地进行数据库操作。 在使用这些JAR文件时,开发人员需要按照以下步骤进行操作: 1. **添加依赖**:将这三个JAR文件添加到...

    ch4.JDBC技术_JAVA数据库_jdbc_canalsj4_

    JDBC架构主要包括四个主要组件:驱动管理器(Driver Manager)、数据库驱动(Database Driver)、JDBC API和数据库系统。驱动管理器负责加载和管理数据库驱动,JDBC API提供了一组接口和类供应用程序调用,而数据库...

    Spring JDBC常用Jar包

    3. **spring-core-3.2.3.RELEASE.jar**: Spring的核心模块,包含了Spring框架的基础组件,如IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)。这两个概念是Spring框架的核心,使你...

Global site tag (gtag.js) - Google Analytics