Spring JDBC最佳实践

openkk 10年前
     <p>Spring提供了两种使用JDBC API的最佳实践,一种是以JdbcTemplate为核心的基于Template的JDBC的使用方式,另一种则是在JdbcTemplate基础之上的构建的基于操作对象的JDBC的使用方式。</p>    <p>基于Template的JDBC的使用方式<br /> 该使用方式的最初设想和原型,需要追溯到Rod Johnson在03年出版的Expert One-on-One J2EE Design and Development,在该书的Practical Data Access(数据访问实践)中,Rod针对JDBC使用中的一些问题提出了一套改进的实践原型,并最终将该原型完善后在Spring框架中发布。</p>    <p>JDBC的尴尬<br /> JDBC作为Java平台的访问关系数据库的标准,其成功是 有目共睹的。几乎所有java平台的数据访问,都直接或者间接的使用了JDBC,它是整个java平台面向关系数据库进行数据访问的基石。<br /> 作为一个标准,无疑JDBC是很成功的,但是要说JDBC在使用过程当中多么的受人欢迎,则不尽然了。JDBC主要是面向较为底层的数据库操作,所以在设计的过程当中 ,比较的贴切底层以提供尽可能多的功能特色。从这个角度来说,JDBC API的设计无可厚非。可是,过于贴切底层的API的设计,对于开发人员则未必是一件好事。即使执行一个最简单的查询,开发人员也要按照API的规矩写上一大堆雷同的代码,如果不能合理的封装使用JDBC API,在项目中使用JDBC访问数据所出现的问题估计会使人发疯!<br /> 对于通常的项目开发来说,如果层次划分很明确,数据访问逻辑一般应该在DAO层中实现。根据功能模块的划分,可能每个开发人员都会分得或多或少的实现相应的DAO的任务,假设开发人员A在分得了DAO实现任务后进行开发,他或许开发了如下所示的代码:<br /> </p>    <pre class="brush:java; toolbar: true; auto-links: false;">package com.google.spring.jdbc;  import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement;  import javax.sql.DataSource;  import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;  public class DaoWithA implements IDao {   private final Log logger = LogFactory.getLog(DaoWithA.class);  private DataSource dataSource = null;    public DataSource getDataSource()  {   return dataSource;  }   public void setDataSource(DataSource dataSource)  {   this.dataSource = dataSource;  }   @Override  public int updateSomething(String sql)  {   int count;   Connection conn = null;   Statement stmt = null;   try   {    conn = getDataSource().getConnection();    stmt = conn.createStatement();    count = stmt.executeUpdate(sql);    stmt.close();    stmt = null;   }    catch (SQLException e)   {    throw new RuntimeException(e);       }   finally   {    if(stmt!=null)    {     try     {      stmt.close();     }      catch (SQLException ex)     {      logger.warn("fail to close statement:"+ex);     }    }    if(conn!=null)    {     try     {      conn.close();     }      catch (Exception ex)     {      logger.warn("failed to close Connection:"+ex);     }    }   }   return count;  }  }</pre>    <p></p> 而B所负责的DAO的实现中,可能也有类似的更新的操作。无疑,B也要像A这样,在他的DAO实现类中写一大堆同样的JDBC代码,类似的情况还可能扩展到C、D等开发人员。如果每个开发人员都能严格的按照JDBC的编程规范开发还好,但是事实是,一个团队中的开发人员是有差别的。    <br /> 这其实只是API的使用过程中的一个插曲,当你看到应用程序中成百的使用JDBC实现类的时候,会发现如下的问题:    <br /> 1、Statement使用完没有关闭,而是想着让Connection关闭的时候一并关闭,可是并非所有的驱动程序都有这样的行为。    <br /> 2、创建了多个ResultSet或者Statement,只清理了最外层的,忽视了里层的。    <br />    <p>3、忘记关闭Connection。<br /> JDBC规范在指定数据库访问异常的时候也没有能够进行的很彻底:<br /> 1、将异常类型定义为SQLException是一个值得商榷的地方。<br /> 2、SQLExcpetion没有采用将具体的异常情况子类化,以进一步抽象不同的数据访问的情况,而是采用ErrorCode的方式来区分访问过程中所出现的不同异常情况,其实这也没什么,只要能区分出具体的错误就行,但是JDBC规范却把ErrorCode的规范留给了数据库提供商,这导致了不同的数据库供应商对应了不同的ErrorCode,进而应用程序在捕获到SQLException后,还要看当前用的是什么数据库。<br /> 针对以上问题,Spring提供了相应的解决方案帮助我们提高开发效率! </p>    <p></p>