Spring JDBC抽象框架简化Web数据库开发

web|数据|数据库

  一. 引言

  Spring是一个轻量级的应用程序框架。在许多情况中,Spring都能够良好地代换传统的由Java EE应用程序服务器所提供的服务。Spring既是综合性的也是模块化的。基于其分层架构,它能够使开发者灵活地单独使用其任何一部分。Spring由许多模块组成,例如IoC容器,AOP,MVC,持久性,DAO和remoting。这些模块都是相当松耦合的:其中,一些模块的使用根本不需要另一些模块。以前,简直还没有象Spring应用程序这样的:你可以选择使用一些,大多数,或所有的Spring框架支持的组件来构建你的应用程序。

  Spring框架所提供的JDBC支持与其它Spring部分并非是紧耦合的,这极有利于代码的可维护性。本文将向你展示任何直接使用JDBC(也即是,不通过一些O/R映射框架本身使用JDBC)的应用程序是如何从Spring中受益的。

  二. 传统型JDBC

  传统型JDBC有许多积极的方面使之在许多J2SE和J2EE应用程序开发中占有重要地位。然而,也有一些特征使其难于使用:

  · 开发者需要处理大量复杂的任务和基础结构,例如大量的try-catch-finally-try-catch块。

  · 应用程序需要复杂的错误处理以确定连接在使用后被正确关闭,这样以来使得代码变得冗长,膨胀,并且重复。

  · JDBC中使用了极不明确性的SQLException异常。

  · JDBC没有引入具体的异常子类层次机制。

  相应于任何一种错误,都只是抛出SQLException异常-无论它来源于JDBC驱动程序还是来源于数据库,这使得程序员很难理解到底是哪里实际出现了错误。例如,如果SQL对象是无效的或已经被锁定,那么将抛出一个SQLException异常。调试这样的异常需要一定的时间来检查SQL状态值和错误代码。更有甚者,SQL状态值和错误代码的含义在各种数据库之间都有些差别。

  事实证明,编写JDBC代码并不是一项容易的工作-存在大量的重复性的工作。为了说明问题,下面是一个例子-使用传统型JDBC来从数据库中得到一个可用任务的列表。

package com.spring.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
public class TraditionalJDBC {
 public Vector getTasksNames() {
  Connection con = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  Vector task = new Vector();
  try {
   con = getConnection();
   pstmt = con.prepareStatement( "select TASKNAME from tasks");
   rs = pstmt.executeQuery();
   while (rs.next()) {
    task.add(rs.getString(1));
   }
  } catch (SQLException e) {
   System.out.println(e);
  } finally {
   try {
    rs.close();
    pstmt.close();
    con.close();
   } catch (SQLException e1) {
    System.out.println(e1);
   }
  }
  return task;
 }
 private Connection getConnection()throws SQLException {
  try {
   DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
   return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl",
"scott","tiger");
  } catch (SQLException sqle) {
   System.out.println(sqle);
   return null;
  }
 }
 public static void main(String[] args) {
  TraditionalJDBC obj = new TraditionalJDBC();
  Vector task = obj.getTasksNames();
  for (int i = 0; i < task.size(); i++) {
   System.out.println(task.elementAt(i));
  }
 }
}
  除了实际查询数据库的SQL代码外,上面的示例中需要巨大数量的例程代码。getConnection()方法与我们的任务无关,而即使是getTasksNames()方法也仅包含特定于当前任务的两行代码。剩下的都是一些普通的复杂的任务代码。

  JDBC的许多积极方面使得它在许多J2SE和J2EE应用程序中仍然占有重要地位。然而,正如你所见,有一些特征使其比我们可能想像的要更难于使用。JDBC这些乏味并且有时挫败人性的特征已经导致出现了许多公共的可以利用的JDBC抽象框架(例如SQLExecutor和Apache Jakarta Commons DBUtils),还有数不清的自家生产性JDBC应用程序框架。一种公共的可以利用的JDBC抽象框架正是Spring框架的JDBC抽象。

  三. Spring JDBC简介

  Spring所提供的JDBC抽象框架由四个不同的包组成:

  · 核心包包含JdbcTemplate。这个类是一个基础类之一-由Spring框架的JDBC支持提供并使用。

  · 数据源包是实现单元测试数据库存取代码的重要的一部分。它的DriverManagerDataSource能够以一种类似于你已经习惯于JDBC中的用法:只要创建一个新的DriverManagerDataSource并且调用setter方法来设置DriverClassName,Url,Username和Password。

  · 对象包中包含类,用于描述RDBMS查询、更改和存储过程为线程安全的、可重用的对象。

  · 支持包-你可以从这里找到SQLException翻译功能和一些工具类。

  1) 模板设计模式

  Spring JDBC实现模板设计模式,这意味着,代码中的重复的复杂的任务部分是在模板类中实现的。这种方式简化了JDBC的使用,因为由它来处理资源的创建和释放。这有助于避免普通错误,例如忘记关闭连接等。它执行核心JDBC工作流任务,如语句创建和执行,而让应用程序代码来提供SQL并且提取结果。

  2) Spring JDBC异常处理

  Spring框架特别强调在传统型JDBC编程中所面临的与下列方案有关的问题:

  · Spring提供一个抽象异常层,把冗长并且易出错误的异常处理从应用程序代码移到由框架来实现。框架负责所有的异常处理;应用程序代码则能够专注于使用适当的SQL提取结果。

  · Spring提供了一个重要的异常类层次,以便于你的应用程序代码中可以使用恰当的SQLException子类。

  借助于一个抽象异常层,我们成功地实现了数据库独立性而不必改变异常处理。例如,如果你把你的数据库从PostgreSQL改变为Oracle,那么你不必把异常处理从OracleDataException改变到PostgresDataException。Spring能够捕获应用程序服务器特定的异常并抛出一个Spring数据异常。

  当处理异常时,Spring检查来自一个数据库连接的元数据可用性以决定数据库产品。它使用这种知识来把SQLException映射到其自己异常层次中的具体的异常上。因此,我们不需要担心专门性的SQL状态或错误代码问题;Spring的数据存取异常不是JDBC特定的,因此你的DAO不必绑定到JDBC(由于其可能抛出的异常)。

  四. Spring JDBC示例

  在下面两个列表中,我们将使用前面用传统型JDBC实现的业务逻辑为例并且展示使用Spring JDBC版本是多么容易。首先,我们从一个简单的接口开始。

package com.spring.jdbc;
import java.util.List;
public interface TasksDAO {
 public List getTasksNames();
}
  接下来,我们提供针对于TasksDAO接口的一种实现。

package com.spring.jdbc;
import java.util.Iterator;
import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.RowMapperResultReader;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class TasksJdbcDAO extends JdbcDaoSupport
implements TasksDAO {

 public List getTasksNames() {
  JdbcTemplate jt = getJdbcTemplate();
  return jt.query("select TASKNAME from tasks",
new RowMapperResultReader(new TasksRowMapper()));
 }
 class TasksRowMapper implements RowMapper {
  public Object mapRow(ResultSet rs, int index)
  throws SQLException {
   return rs.getString(1);
  }
 }
 public static void main(String[] args)throws Exception {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("SpringConfig.xml");
  DataSource ds =(DataSource) ctx.getBean("dataSourceDBDirect");
  TasksJdbcDAO taskDao = new TasksJdbcDAO();

  taskDao.setDataSource(ds);
  Iterator tskIter = taskDao.getTasksNames().iterator();
  while (tskIter.hasNext()) {
   System.out.println(tskIter.next().toString());
  }
 }
}

  在上面的例子中,普通的和复杂的任务代码已经被移交到框架中。还应注意,借助于Spring JDBC,我们如何利用控制反转(IoC)容器来提供一种DataSource-我们仅把它注入到TasksJdbcDAO对象中。

  控制反转背后的概念通常被表达为"不要找我,让我找你好了"。IoC把一些任务移交到了框架中,并且脱离出了应用程序代码。不是让你的代码调用一个传统的类库,而是一个IoC框架调用你的代码。存在于许多API中的生命周期回调,例如相应于会话EJB的setSessionContext()方法,正是展示了这种方法。

  DataSource必须被注入到这个类中(或者其超类中),这是通过setDataSource()方法实现的。所有配置细节都远离了业务逻辑或客户端代码;这增加你的应用程序的松耦合性并因此而提高了程序的可测试性和可维护性。作为选择,我们还能在JNDI或servlet容器中建立一个DataSource,并用编程方式来检索它,然后把它注入到DAO对象中。下面是一个你可以使用的示例Spring bean配置文件-SpringConfig.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSourceDBDirect"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
destroy-method="close">
 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
 <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
 <property name="username" value="scott"/>
 <property name="password" value="tiger"/>
</bean>
</beans>
  这个文件指示Spring bean容器实例化一个dataSourceDBDirect bean-它基于org.springframework.jdbc.datasource.DriverManagerDataSource类创建。

  1) 基于Spring JDBC实现一个业务层

  我们已经看到了一个简单的使用Spring JDBC的例子,在这种情况下,它从Spring BeanFactory(控制反转容器)中得到极少的帮助。现在,我们将超越这个简单的例子。让我们来探讨一下如何基于Spring JDBC实现业务服务。首先,让我们创建一个客户端-一个为终端用户提供输出的应用程序。该客户端使用了一个服务,一个遵守下面的Service接口的业务服务:

package com.spring.jdbc;
import java.util.List;
public interface Service {
 public List getTasksNames();
 public void setTasksDao(TasksDAO taskDAO);
}
  客户端需要存取一个业务服务对象。它将使用Spring BeanContainer来"抓住"这样的一个服务对象。客户端仅能针对接口编程并且依赖容器来提供一种实际的实现。而且,这个ServiceImpl类必须实现所有的存在于业务服务接口中的方法。该代码看上去如下所示:

package com.spring.jdbc;
import java.util.List;
public class ServiceImpl implements Service{
 TasksDAO taskDAO;
 public void setTasksDao(TasksDAO taskDAO)
 {
  this.taskDAO=taskDAO;
 }
 public List getTasksNames()
 {
  List tasks = taskDAO.getTasksNames();
  return tasks;
 }
}
  你应该已经注意到,该服务需要一个TasksJdbcDAO。反过来,这个对象实现了TasksDAO接口。因此,我们将通过BeanFactory来把DAO注入到该服务中。在此,我们碰巧有一个TasksJdbcDAO类-bean工厂可以使用它来实现这一目的。然而,既然这个类派生于JdbcDaoSupport,那么我们知道我们需要注入一个DataSource或让bean工厂为我们注入该DataSource。现在这个bean配置文件看上去如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSourceDBDirect"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
destroy-method="close">
 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
 <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
 <property name="username" value="scott"/>
 <property name="password" value="tiger"/>
</bean>
<bean id="tasksDAO" class="com.spring.jdbc.TasksJdbcDAO">
 <property name="dataSource">
  <ref local="dataSourceDBDirect"/>
 </property>
</bean>
<bean id="service" class="com.spring.jdbc.ServiceImpl">
 <property name="tasksDao">
  <ref local="tasksDAO"/>
 </property>
</bean>
</beans>
  我们看到服务bean使得tasksDao bean被注入-它反过来又使dataSourceDBDirect对象被注入。当我们请求服务bean时,我们通过一个具有DataSource的DAO得到它。至此,一切就绪。因此,当客户端存取bean容器以得到服务对象时,会发生什么呢?该bean容器实例化并且注入一个DataSource和一个TasksDAO-在把服务返回到客户端之前。现在,我们的客户端变得相当简单了。它需要与BeanFactory进行通讯,"抓住"一个服务对象并处理它:

package com.spring.jdbc;
import java.util.Iterator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client extends RuntimeException {
 public static void main(String[] args) throws Exception {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("SpringConfig.xml");
  Service service = (Service)ctx.getBean("service");
  Iterator tskIter = service.getTasksNames().iterator();
  while (tskIter.hasNext()) {
   System.out.println(tskIter.next().toString());
  }
 }
}
  你必须注意,在此Client派生于RuntimeException异常类。Spring抛出了RuntimeExceptions而不是检查的异常-RuntimeExceptions不应该被捕获。由于在你的代码中捕获所有异常是一种复杂的任务,所以Spring开发者决定抛出RuntimeExceptions以便实现如果你不捕获一个异常的话,那么你的应用程序将会中断而且用户会得到该应用程序异常。使用它们的第二个理由是,绝大多数异常都是不可恢复的,因此你的应用程序逻辑不能以任何方式来再次处理它们。

  五. 另外的优点

  除了上面描述的Spring框架带给JDBC中的优点外,与你的JDBC应用程序一起使用Spring框架还存在另外一些优点。这些优点包括:

  · Spring框架提供了

  org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor接口和这个接口的一些实现(例如SimpleNativeJdbcExtractor)。对于经由一个Oracle连接或ResultSet访问Oracle特征的情况来说,这些内容是非常有用的。

  · 对于创建oracle.sql.BLOB(二进制大型对象)和oracle.sql.CLOB(字符大型对象)实例来说,Spring提供了类org.springframework.jdbc.support.lob.OracleLobHandler。

  · Spring提供的OracleSequenceMaxValueIncrementer类提供了一个Oracle序列的下一个值。它有效地提供了与你直接使用下列命令:"select someSequence.nextval from dual"(其中,someSequence是在Oracle数据库中的你的序列的名字)所提供的一样的信息。这种方法的优点是,DataFieldMaxValueIncrementer接口可以用于一个DAO层次中而不必紧密地耦合于Oracle特定的实现。

  六. 结论

  本文集中讨论了使用Spring来编写更可维护的和更不易出现错误的JDBC代码。Spring JDBC提供了一些优点,例如更为干净的代码,更好的异常与资源处理,并且能够集中于业务问题而不是复杂的任务代码。另外,值得注意的是,使用Spring框架能够使用极少的代码就可以实现实质上与传统型JDBC相同的功能。

时间: 2016-07-07

Spring JDBC抽象框架简化Web数据库开发的相关文章

使用decj简化Web前端开发(一)

声明式Javascript动态加载和浏览器事件绑定 引言 Web前端开发中,开发人员经常需要处理一些常规问题,如: 在页面中引用多个相互存在依赖关系的Javascript文件 在页面中引用CSS文件 浏览器事件绑定 表单的数据填充.数据打包提交.数据校验和格式化 页面初始化逻辑 采用传统的命令式编程范式来处理这些问题时,开发人员不得不反复地通过编写代码调用相关API来完成这些常规任务.事实上,开发人员的主要精力应该集中在业务逻辑实现上,而非在这些常规任务上过多消耗时间.声明式编程范式可以帮助开发

使用decj简化Web前端开发(三) 声明式国际化

引言 本期将介绍decj的国际化(I18N)支持,包括声明式多语言支持和声明式CSS文件动态按需加载. 声明式CSS文件按需加载 使用decj框架,开发人员只需要在模块定义中声明模块所需的各个CSS文件,即可实现这些CSS在该模块被加载时而被动态加载,而无需事先在页面中添加link标签来引用各个CSS文件. 模块定义的css属性用于声明模块所需的各个CSS文件.该属性值是一个字符串数组,其各个元素为所要加载的CSS文件的URL.如果只需要加载一个CSS文件,css属性的值也可以是一个字符串.如清

使用decj简化Web前端开发(二) 声明式表单增强和页面初始化

引言 表单(Form)是Web应用中数据展现和收集常用的HTML元素.开发人员经常需要处理表单的数据填充.数据校验和格式化以及数据打包.另外,页面在加载完毕后往往需要执行一段初始化逻辑.本期将介绍decj对HTML表单的声明式增强和声明式页面/模块初始化这2个特性. 声明式表单功能增强 decj以声明式编程的方式对表单数据展现和收集功能进行增强.在数据展现方面,decj支持根据指定的数据自动将数据填充到表单中.对表单字段值进行自动格式化.在数据收集方面,decj支持对表单字段值进行自动校验.对表

使用spring jdbc template简化jdbc数据库操作实例代码

文章地址: http://blog.csdn.net/5iasp/article/details/12206793 作者: javaboy2012 Email:yanek@163.com qq:    1046011462   使用spring jdbc template简化jdbc数据库操作实例代码   包括如下几个类:   1. DAO接口   package com.test; import java.util.List; import org.springframework.jdbc.c

为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?

为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?  今年我一直在思考web开发里的前后端分离的问题,到了现在也颇有点心得了,随着这个问题的深入,再加以现在公司很多web项目的控制层的技术框架由struts2迁移到springMVC,我突然有了一个新的疑问无法得到正确的解释,为什么我们现在做java的web开发,会选择struts2或者springMVC这样的框架,而不是使用servlet加jsp这样的技术呢?特别是现在我们web的前端页面都是使用

简化Web开发的12个HTML5-CSS框架

HTML5已经在Web开发中越来越流行.并且现在大部分流行的浏览器包括Firefox 6, Google Chrome, IE9等都支持HTML5. 利用框架能够帮助Web开发人员快速进行设计和开发.一个HTML5的框架提供了许多功能,如优美的排版,视频播放器,表单验证等,使开发人员能够轻松地 开发Web应用程序. 1. 52 Framework : HTML5-CSS3 Framework 该框架支持HTML5和CSS3,支持目前所有的浏览器.该框架充分利用了HTML5所有的优势.在网页设计师

基于Spring框架的WebSphere应用开发

web 概览 轻量级的企业应用开发越来越受到广大J2EE应用开发者的追捧,而Spring框架又是轻量级容器的杰出代表.由于Spring的使用日渐广泛,因此已有许多基于WebSphere应用服务器(WAS)的应用采用了Spring框架.本文首先介绍使用Spring开发Web应用的基本问题,然后结合WebSphere应用服务器,讲述Spring应用如何结合容器提供的服务.文章目的是与大家一起探讨如何更好的采用Spring框架开发基于WebSphere应用服务器的应用. 1.Spring框架的主要思想

数据库开发资源总汇 分享10个JDBC开源驱动器

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 JDBC,即数据库连接,用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问.JDBC由一组用Java语言编写的类和接口组成,为开发人员提供一个标准的API,使其能够用纯Java API编写数据库应用程序.下面,IDC评述网整理了10个JDBC驱动工具,供大家参考. 1. Excel JDBC Driver Excel JD

【框架】[Spring] 基于Spring框架的Web应用演示(附带cglib工具进行动态代理)

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 前言: Spring也差不多学了Ioc控制反转和实现AOP技术的两种方式了,分享一个学习Spring,用来入门挺好的例子. 如果你是刚刚学习Spring,那么此实例应该可以很好的帮助你应用Spring到Web项目中. 里面的DAO层-提交数据库的事务我并没有使用Spring 的注解功能,而是用spring的AOP来实现的.这样更灵活,其实,框架为我们做的事越多,我们就越受框架的约束