spring_对JDBC的支持

7.1  概述

7.1.1  JDBC回顾

       传统应用程序开发中,进行JDBC编程是相当痛苦的,如下所示:

 

java代码:
Java代码   收藏代码
  1. //cn.javass.spring.chapter7. TraditionalJdbcTest  
  2. @Test  
  3. public void test() throws Exception {  
  4.     Connection conn = null;  
  5.     PreparedStatement pstmt = null;  
  6.     try {  
  7.       conn = getConnection();              //1.获取JDBC连接  
  8.                                        //2.声明SQL  
  9.       String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";  
  10.       pstmt = conn.prepareStatement(sql);    //3.预编译SQL  
  11.       ResultSet rs = pstmt.executeQuery();   //4.执行SQL  
  12.       process(rs);                       //5.处理结果集  
  13.       closeResultSet(rs);                 //5.释放结果集  
  14.       closeStatement(pstmt);              //6.释放Statement  
  15.       conn.commit();                    //8.提交事务  
  16.     } catch (Exception e) {  
  17.       //9.处理异常并回滚事务  
  18.       conn.rollback();  
  19.       throw e;  
  20.     } finally {  
  21.       //10.释放JDBC连接,防止JDBC连接不关闭造成的内存泄漏  
  22.       closeConnection(conn);  
  23.     }  
  24. }  

 

       以上代码片段具有冗长、重复、容易忘记某一步骤从而导致出错、显示控制事务、显示处理受检查异常等等。

       有朋友可能重构出自己的一套JDBC模板,从而能简化日常开发,但自己开发的JDBC模板不够通用,而且对于每一套JDBC模板实现都差不多,从而导致开发人员必须掌握每一套模板。

       Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发,而且如果各个公司都使用该抽象框架,开发人员首先减少了学习成本,直接上手开发,如图7-1所示。

 

图7-1 Spring JDBC与传统JDBC编程对比

7.1.2  Spring对JDBC的支持

       Spring通过抽象JDBC访问并提供一致的API来简化JDBC编程的工作量。我们只需要声明SQL、调用合适的Spring JDBC框架API、处理结果集即可。事务由Spring管理,并将JDBC受查异常转换为Spring一致的非受查异常,从而简化开发。

       Spring主要提供JDBC模板方式、关系数据库对象化方式和SimpleJdbc方式三种方式来简化JDBC编程,这三种方式就是Spring JDBC的工作模式:

  •  JDBC模板方式:Spring JDBC框架提供以下几种模板类来简化JDBC编程,实现GoF模板设计模式,将可变部分和非可变部分分离,可变部分采用回调接口方式由用户来实现:如JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate。
  • 关系数据库操作对象化方式:Spring JDBC框架提供了将关系数据库操作对象化的表示形式,从而使用户可以采用面向对象编程来完成对数据库的访问;如MappingSqlQuery、SqlUpdate、SqlCall、SqlFunction、StoredProcedure等类。这些类的实现一旦建立即可重用并且是线程安全的。
  • SimpleJdbc方式:Spring JDBC框架还提供了SimpleJdbc方式来简化JDBC编程,SimpleJdbcInsert 、 SimpleJdbcCall用来简化数据库表插入、存储过程或函数访问。

Spring JDBC还提供了一些强大的工具类,如DataSourceUtils来在必要的时候手工获取数据库连接等。

7.1.4    Spring的JDBC架构

Spring JDBC抽象框架由四部分组成:datasource、support、core、object。如图7-2所示。

 

图7-2 Spring JDBC架构图

       support包:提供将JDBC异常转换为DAO非检查异常转换类、一些工具类如JdbcUtils等。

       datasource包:提供简化访问JDBC 数据源(javax.sql.DataSource实现)工具类,并提供了一些DataSource简单实现类从而能使从这些DataSource获取的连接能自动得到Spring管理事务支持。

       core包:提供JDBC模板类实现及可变部分的回调接口,还提供SimpleJdbcInsert等简单辅助类。

       object包:提供关系数据库的对象表示形式,如MappingSqlQuery、SqlUpdate、SqlCall、SqlFunction、StoredProcedure等类,该包是基于core包JDBC模板类实现。


7.2  JDBC模板类

7.2.1  概述

       Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式。

 

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

 

       JdbcTemplate类对可变部分采用回调接口方式实现,如ConnectionCallback通过回调接口返回给用户一个连接,从而可以使用该连接做任何事情、StatementCallback通过回调接口返回给用户一个Statement,从而可以使用该Statement做任何事情等等,还有其他一些回调接口如图7-3所示。

 

图7-3 JdbcTemplate支持的回调接口

 

Spring除了提供JdbcTemplate核心类,还提供了基于JdbcTemplate实现的NamedParameterJdbcTemplate类用于支持命名参数绑定、 SimpleJdbcTemplate类用于支持Java5+的可变参数及自动装箱拆箱等特性。

 

7.2.3         传统JDBC编程替代方案

前边我们已经使用过传统JDBC编程方式,接下来让我们看下Spring JDBC框架提供的更好的解决方案。

1)准备需要的jar包并添加到类路径中:

 

java代码:
Java代码   收藏代码
  1. //JDBC抽象框架模块  
  2. org.springframework.jdbc-3.0.5.RELEASE.jar       
  3. //Spring事务管理及一致的DAO访问及非检查异常模块   
  4. org.springframework.transaction-3.0.5.RELEASE.jar   
  5. //hsqldb驱动,hsqldb是一个开源的Java实现数据库,请下载hsqldb2.0.0+版本  
  6. hsqldb.jar  

 

2)传统JDBC编程替代方案:

在使用JdbcTemplate模板类时必须通过DataSource获取数据库连接,Spring JDBC提供了DriverManagerDataSource实现,它通过包装“DriverManager.getConnection”获取数据库连接,具体DataSource相关请参考【7.5.1控制数据库连接】。

 

java代码:
Java代码   收藏代码
  1. package cn.javass.spring.chapter7;  
  2. import java.sql.ResultSet;  
  3. import java.sql.SQLException;  
  4. import org.junit.AfterClass;  
  5. import org.junit.BeforeClass;  
  6. import org.junit.Test;  
  7. import org.springframework.jdbc.core.JdbcTemplate;  
  8. import org.springframework.jdbc.core.RowCallbackHandler;  
  9. import org.springframework.jdbc.datasource.DriverManagerDataSource;  
  10. public class JdbcTemplateTest {  
  11.     private static JdbcTemplate jdbcTemplate;  
  12.     @BeforeClass  
  13.     public static void setUpClass() {  
  14.         String url = "jdbc:hsqldb:mem:test";  
  15.         String username = "sa";  
  16.         String password = "";  
  17.         DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);  
  18.         dataSource.setDriverClassName("org.hsqldb.jdbcDriver");  
  19.         jdbcTemplate = new JdbcTemplate(dataSource);  
  20.     }  
  21.     @Test  
  22.     public void test() {  
  23.         //1.声明SQL  
  24.         String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";  
  25.         jdbcTemplate.query(sql, new RowCallbackHandler() {  
  26.             @Override  
  27.             public void processRow(ResultSet rs) throws SQLException {  
  28.                 //2.处理结果集  
  29.                 String value = rs.getString("TABLE_NAME");  
  30.                 System.out.println("Column TABLENAME:" + value);  
  31.             }  
  32.         });  
  33.     }  
  34. }  
  35.    


接下来让我们具体分析一下:

1)  jdbc:hsqldb:mem:test:表示使用hsqldb内存数据库,数据库名为“test”。

2)  public static void setUpClass():使用junit的@BeforeClass注解,表示在所以测试方法之前执行,且只执行一次。在此方法中定义了DataSource并使用DataSource对象创建了JdbcTemplate对象。JdbcTemplate对象是线程安全的。

3)  JdbcTemplate执行流程:首先定义SQL,其次调用JdbcTemplate方法执行SQL,最后通过RowCallbackHandler回调处理ResultSet结果集。

Spring JDBC解决方法相比传统JDBC编程方式是不是简单多了,是不是只有可变部分需要我们来做,其他的都由Spring JDBC框架来实现了。

接下来让我们深入JdbcTemplate及其扩展吧。

 

7.2.4         JdbcTemplate

       首先让我们来看下如何使用JdbcTemplate来实现增删改查。

一、首先创建表结构:

 

java代码:
Java代码   收藏代码
  1. //代码片段(cn.javass.spring.chapter7.JdbcTemplateTest)  
  2. @Before  
  3. public void setUp() {  
  4.    String createTableSql = "create memory table test" + "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " + "name varchar(100))";  
  5.    jdbcTemplate.update(createTableSql);  
  6. }  
  7. @After  
  8. public void tearDown() {  
  9.   String dropTableSql = "drop table test";  
  10.   jdbcTemplate.execute(dropTableSql);  
  11. }  

 

1)  org.junit包下的@Before和@After分别表示在测试方法之前和之后执行的方法,对于每个测试方法都将执行一次;

 

2)  create memory table test表示创建hsqldb内存表,包含两个字段id和name,其中id是具有自增功能的主键,如果有朋友对此不熟悉hsqldb可以换成熟悉的数据库。

 

 

二、定义测试骨架,该测试方法将用于实现增删改查测试:

 

java代码:
Java代码   收藏代码
  1. @Test  
  2. public void testCURD() {  
  3.     insert();  
  4.     delete();  
  5.     update();  
  6.     select();  
  7. }  

 

三、新增测试:

 

java代码:
Java代码   收藏代码
  1. private void insert() {  
  2.   jdbcTemplate.update("insert into test(name) values('name1')");  
  3.   jdbcTemplate.update("insert into test(name) values('name2')");  
  4.   Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));  
  5. }  

 

四、删除测试:

 

java代码:
Java代码   收藏代码
  1. private void delete() {  
  2.   jdbcTemplate.update("delete from test where name=?"new Object[]{ "name2"});  
  3.   Assert.assertEquals(1, jdbcTemplate.queryForInt("select count(*) from test"));  
  4. }  

 

五、更新测试:

 

java代码:
Java代码   收藏代码
  1. private void update() {  
  2.   jdbcTemplate.update("update test set name='name3' where name=?"new Object[]{ "name1"});  
  3.   Assert.assertEquals(1, jdbcTemplate.queryForInt("select count(*) from test where name='name3'"));  
  4. }  

 

 

六、查询测试:

 

java代码:
Java代码   收藏代码
  1. private void select() {  
  2.   jdbcTemplate.query("select * from test"new RowCallbackHandler(){  
  3.     @Override  
  4.     public void processRow(ResultSet rs) throws SQLException {  
  5.       System.out.print("====id:" + rs.getInt("id"));  
  6.       System.out.println(",name:" + rs.getString("name"));  
  7.     }  
  8.   });  
  9. }  

 

       看完以上示例,大家是否觉得JdbcTemplate简化了我们很多劳动力呢?接下来让我们深入学习一下JdbcTemplate提供的方法。

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

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

 

JdbcTemplate类支持的回调类:

  • 预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句;

         PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的PreparedStatement;

         CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的CallableStatement;

  • 预编译语句设值回调:用于给预编译语句相应参数设值;

         PreparedStatementSetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值;

         BatchPreparedStatementSetter:;类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小;

  • 自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作;

         ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;

         StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作;

         PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作;

         CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作;

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

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

         RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。

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

 

接下来让我们看下具体示例吧,在示例中不可能介绍到JdbcTemplate全部方法及回调类的使用方法,我们只介绍代表性的,其余的使用都是类似的;

 

 

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

 

java代码:
Java代码   收藏代码
  1. @Test  
  2. public void testPpreparedStatement1() {  
  3.   int count = jdbcTemplate.execute(new PreparedStatementCreator() {  
  4.      @Override  
  5.      public PreparedStatement createPreparedStatement(Connection conn)  
  6.          throws SQLException {  
  7.          return conn.prepareStatement("select count(*) from test");  
  8.      }}, new PreparedStatementCallback<Integer>() {  
  9.      @Override  
  10.      public Integer doInPreparedStatement(PreparedStatement pstmt)  
  11.          throws SQLException, DataAccessException {  
  12.          pstmt.execute();  
  13.          ResultSet rs = pstmt.getResultSet();  
  14.          rs.next();  
  15.          return rs.getInt(1);  
  16.       }});      
  17.    Assert.assertEquals(0, count);  
  18. }  
  19.    

 

首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定如何执行该PreparedStatement。此处我们使用的是execute方法。

 

2)预编译语句设值回调使用:

 

java代码:
Java代码   收藏代码
  1.       
  2. @Test  
  3. public void testPreparedStatement2() {  
  4.   String insertSql = "insert into test(name) values (?)";  
  5.   int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {  
  6.       @Override  
  7.       public void setValues(PreparedStatement pstmt) throws SQLException {  
  8.           pstmt.setObject(1"name4");  
  9.   }});  
  10.   Assert.assertEquals(1, count);      
  11.   String deleteSql = "delete from test where name=?";  
  12.   count = jdbcTemplate.update(deleteSql, new Object[] { "name4"});  
  13.   Assert.assertEquals(1, count);  
  14. }  

 

      通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into test(name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。JdbcTemplate也提供一种更简单的方式“update(String sql, Object... args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter。

 

3)结果集处理回调:

 

java代码:
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_驿站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值