天天看点

Spring JDBC、Spring JdbcTemplate 、

Spring JDBC抽象框架所带来的价值将在以下几个方面得以体现:(注:使用了Spring JDBC抽象框架之后,应用开发人员编码工作简单很多。)

  1. 定义数据库连接参数
  2. 打开数据库连接
  3. 声明SQL语句
  4. 预编译并执行SQL语句
  5. 遍历查询结果(如果需要的话)
  6. 处理每一次遍历操作
  7. 处理抛出的任何异常
  8. 处理事务
  9. 关闭数据库连接

Spring将替我们完成所有使用JDBC API进行开发的单调乏味的、底层细节处理工作。

有以下工作模式可以选择:

使用Spring进行基本的JDBC访问数据库有多种选择。Spring至少提供了三种不同的工作模式:JdbcTemplate, 一个在Spring2.5中新提供的SimpleJdbc类能够更好的处理数据库元数据; 还有一种称之为RDBMS Object的风格的面向对象封装方式, 有点类似于JDO的查询设计。 我们在这里简要列举你采取某一种工作方式的主要理由. 不过请注意, 即使你选择了其中的一种工作模式, 你依然可以在你的代码中混用其他任何一种模式以获取其带来的好处和优势。 所有的工作模式都必须要求JDBC 2.0以上的数据库驱动的支持, 其中一些高级的功能可能需要JDBC 3.0以上的数据库驱动支持。

  • JdbcTemplate - 这是经典的也是最常用的Spring对于JDBC访问的方案。这也是最低级别的封装, 其他的工作模式事实上在底层使用了JdbcTemplate作为其底层的实现基础。JdbcTemplate在JDK 1.4以上的环境上工作得很好。
  • NamedParameterJdbcTemplate - 对JdbcTemplate做了封装,提供了更加便捷的基于命名参数的使用方式而不是传统的JDBC所使用的“?”作为参数的占位符。这种方式在你需要为某个SQL指定许多个参数时,显得更加直观而易用。该特性必须工作在JDK 1.4以上。
  • SimpleJdbcTemplate - 这个类结合了JdbcTemplate和NamedParameterJdbcTemplate的最常用的功能,同时它也利用了一些Java 5的特性所带来的优势,例如泛型、varargs和autoboxing等,从而提供了更加简便的API访问方式。需要工作在Java 5以上的环境中。
  • SimpleJdbcInsert 和 SimpleJdbcCall - 这两个类可以充分利用数据库元数据的特性来简化配置。通过使用这两个类进行编程,你可以仅仅提供数据库表名或者存储过程的名称以及一个Map作为参数。其中Map的key需要与数据库表中的字段保持一致。这两个类通常和SimpleJdbcTemplate配合使用。这两个类需要工作在JDK 5以上,同时数据库需要提供足够的元数据信息。
  • RDBMS 对象包括MappingSqlQuery, SqlUpdate and StoredProcedure - 这种方式允许你在初始化你的数据访问层时创建可重用并且线程安全的对象。该对象在你定义了你的查询语句,声明查询参数并编译相应的Query之后被模型化。一旦模型化完成,任何执行函数就可以传入不同的参数对之进行多次调用。这种方式需要工作在JDK 1.4以上。

        Spring Framework的JDBC抽象框架由四个包构成:core、 dataSource、object以及support

 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进行定制的话,可能是它的子类名)。

下面给出一些示例:

JdbcTemplate提供更简单的queryForXXX方法,来简化开发:

//1.查询一行数据并返回int型结果
jdbcTemplate.queryForInt("select count(*) from test");
//2. 查询一行数据并将该行数据转换为Map返回
jdbcTemplate.queryForMap("select * from test where name='name5'");
//3.查询一行任何类型的数据,最后一个参数指定返回结果类型
jdbcTemplate.queryForObject("select count(*) from test", Integer.class);
//4.查询一批数据,默认将每行数据转换为Map
jdbcTemplate.queryForList("select * from test");
//5.只查询一列数据列表,列类型是String类型,列名字是name
jdbcTemplate.queryForList("
select name from test where name=?", new Object[]{"name5"}, String.class);
//6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上
SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");      

还有一些比较深入一些的用法如下:

JdbcTemplate主要提供以下五类方法:

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
  • query方法及queryForXXX方法:用于执行查询相关语句;
  • call方法:用于执行存储过程、函数相关语句

JdbcTemplate类支持的回调类:

结果集处理回调:通过回调处理ResultSet或将ResultSet转换为需要的形式; 

RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs, int rowNum)来完成将每行数据转换为相应的类型。

RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,

                                    在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。

ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集;

下面是例子:public <T> List<T> query(String sql, RowMapper<T> rowMapper)

/**
 * 结果集处理回调
 * <p>
 * 将查询出来的对象,以List的集合的形式返回出来
 * <p>
 * RowMapper接口提供mapRow(ResultSet rs, int rowNum)方法将结果集的每一行转换为一个Object或者map,当然可以转换为其他类.
 */
public void getResultSet() {
    String listSql = " select * from t_cooperation ";
    List listEntity = jdbcTemplate.query(listSql, new RowMapper<Cooperation>() {
        @Override
        public Cooperation mapRow(ResultSet rs, int rowNum) throws SQLException {
            Cooperation coop = new Cooperation();
            coop.setAppId(rs.getString("AppId"));
            coop.setAppKey(rs.getString("AppKey"));
            return coop;
        }
    });
    System.out.println(listEntity.size() + "**************************&&&&&&&");
}      

下面是例子:public void query(String sql, RowCallbackHandler rch)

/**
 * RowCallbackHandler接口也提供方法processRow(ResultSet rs),能将结果集的行转换为需要的形式
 */
public void getResultSet_RowCallbackHandler() {
    String listSql = "select * from t_cooperation ";
    List<Cooperation> list_result = new ArrayList<>();
    jdbcTemplate.query(listSql, new RowCallbackHandler() {
        @Override
        public void processRow(ResultSet rs) throws SQLException {
            Cooperation coo = new Cooperation();
            coo.setAppId(rs.getString("AppId"));
            coo.setAppKey(rs.getString("AppKey"));
            coo.setT_cooperation_remork(rs.getString("t_cooperation1"));
            list_result.add(coo);
        }
    });
}      

下面是例子:public <T> T query(final String sql, final

ResultSetExtractor<T>

/**
 * 先把返回结果声明好,ResultSetExtractor的方法extractData可以自动生成
 *
 * ResultSetExtractor使用回调方法extractData(ResultSet rs)提供给用户整个结果集,让用户决定如何处理该结果
 */
public void getResultSetExtractor(){
    String listSql="select * from t_cooperation ";
    List list_entity=jdbcTemplate.query(listSql, new ResultSetExtractor<List>() {
        @Override
        public List extractData(ResultSet rs) throws SQLException, DataAccessException {
            List result = new ArrayList();
            while (rs.next()){
                Cooperation coo = new Cooperation();
                coo.setAppId(rs.getString("AppId"));
                coo.setAppKey(rs.getString("AppKey"));
                coo.setT_cooperation_remork(rs.getString("t_cooperation1"));
                result.add(coo);
            }
            return result;
        }
    });
    System.out.println("ResultSetExtractor::::::::::::"+list_entity.size());
}      

预编译语句设值回调使用 (批量操作batchupdate或者单个update)

JdbcTemplate的批量操作特性需要实现特定的接口

BatchPreparedStatementSetter来进行的, 通过实现这个接口,并将其传入

batchUpdate方法进行调用。这个接口有两个方法需要实现。一个叫做

getBatchSize来提供当前需要批量操作的数量。另外一个方法是

setValues 允许你为prepared statement设置参数。这个方法将在整个过程中被调用的次数,则取决于你在

getBatchSize中所指定的大小。下面的示例展示了根据传入的list参数更新actor表,而传入的list同时作为批量操作的参数。

public int[] batchUpdate(final List actors) {
    String sql="update t_actor set first_name = ?, last_name = ? where id = ?";
    int[] updateCounts = jdbcTemplate.batchUpdate(sql,new BatchPreparedStatementSetter() {
                public void setValues(PreparedStatement ps, int i) throws SQLException {
                    ps.setString(1, ((Actor)actors.get(i)).getFirstName());
                    ps.setString(2, ((Actor)actors.get(i)).getLastName());
                    ps.setLong(3, ((Actor)actors.get(i)).getId().longValue());
                }
                public int getBatchSize() {
                    return actors.size();
                }
            } );
    return updateCounts;
}      

或者

public void getPrepareStatementSetValue() {
    String insertSql = "insert into t_cooperation (AppKey) value (?)";
    int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps) throws SQLException {
            ps.setObject(1, "testtest");
        }
    });
    System.out.println("setValues:::::" + count);
    if (count == 1) {
        String sql = "delete from  t_cooperation where AppKey=?";
        count = jdbcTemplate.update(sql, new Object[]{"testtest"});
        System.out.println("delete:::::" + count);
    }
}      

预编译语句及存储过程创建回调、自定义功能回调使用

public void getPreparedStatement() {
    int count = jdbcTemplate.execute(new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
            return con.prepareStatement(" select count(*) from t_cooperation ");
        }
    }, new PreparedStatementCallback<Integer>() {
        @Override
        public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
            ps.execute();
            ResultSet rs = ps.getResultSet();
            rs.next();
            return rs.getInt(1);
        }
    });
    System.out.println("count:::::::" + count);
}      

简单学习使用,还有更多,自增长,调用存储过程。。。等

参考原文地址:

http://shouce.jb51.net/spring/jdbc.html#jdbc-introduction