前两天在学习spring框架时,了解到spring框架可以对其他数据访问框架进行整合,今天学习了利用spring框架对JDBC技术的整合应用的基本操作,为了日后复习查看方便,所以在此做以总结,同时也希望对和我一样的初学者能有所帮助。

首先介绍一下spring整合JDBC时操作的基本步骤,如下:

    1.首先,新建一个工程,引入Spring框架相关的开发包和主配置文件,我这里新建了一个web工程,名为SpringJdbc 。
    2.然后引入JDBC的驱动包
    3.这些基本操作完成后,下来先根据数据库中要操作的数据表,编写相关的实体类,如下,与数据库中的COST表相对应,我写了一个Cost实体类:

package com.jeason.entity;

public class Cost {

    private Integer cost_id;
    private String name;
    private Integer base_duration;
    private Double base_cost;
    private Double unit_cost;
    private String status;
    private String descr;
    private Date creatime;
    private Date startime;
    private String cost_type;
    //这里需要添加上述属性的get()和set()方法

    ............

}

    4.编写DAO接口和实现类 (这里的实现类继承自spring为JDBC技术提供的JdbcDAOSupport类,使用其中提供的Template对象对数据库进行增删改查操作),如下几个方法是JdbcTemplate类中的几个常用的方法
      update() ---> 实现增删改操作
      query() ----> 实现查询多行记录
      queryForObject() ----> 实现查询一行记录
      queryForInt() -----> 实现查询一个int值

      我这里写了一个CostDAO接口和JdbcCostDAO实现类,如下是CostDAO类:

package com.jeason.dao;
 public interface CostDAO {
     public List<Cost> findAll();
     public Cost findByID(int costID);
     public void save(Cost cost);     
     public void modify(Cost cost);   
     public void delete(int id);   
 }JdbcCostDAO.java类如下:
package com.jeason.dao.impl;
 
public class JdbcCostDAO extends JdbcDaoSupport implements CostDAO {
     @Override
     public List<Cost> findAll() {
         String findAll = "select * from COST";
         RowMapper rm = new CostRowMapper();
         List<Cost> list = getJdbcTemplate().query(findAll, rm);
         return list;
     }
     @Override
     public Cost findByID(int costID) {
         String findById = "select * from COST where COST_ID=?";
         Object[] params = {costID};
         RowMapper rm = new CostRowMapper();
         Cost cost = (Cost)getJdbcTemplate().queryForObject(findById, params, rm);
         return cost;
     }
     @Override
     public void save(Cost cost) {
         String save = "insert into COST(COST_ID,NAME,BASE_DURATION," +
                                         "BASE_COST,UNIT_COST,STATUS," +
                                         "DESCR,CREATIME,COST_TYPE) " +
                                         "values(COST_SEQ.nextval,?,?,?,?,?,?,?,?)";
         Object[] params = {cost.getName(),cost.getBase_duration(),
                     cost.getBase_cost(),cost.getUnit_cost(),cost.getStatus(),
                     cost.getDescr(),cost.getCreatime(),cost.getStartime(),
                     cost.getCost_type()};
         getJdbcTemplate().update(save, params);
     }
     @Override
     public void modify(Cost cost) {
         String modify = "update COST set NAME=?,BASE_DURATION=?," +
                 "BASE_COST=?,UNIT_COST=?,STATUS=?" +
                 "DESCR=?,CREATIME=?,STARTIME=?,COST_TYPE=?" +
                 "where COST_ID=?";
         Object[] params = new Object[]{cost.getName(),cost.getBase_duration(),
                       cost.getBase_cost(),cost.getUnit_cost(),
                       cost.getDescr(),cost.getCreatime(),cost.getStartime(),
                       cost.getCost_type(),
                       cost.getCost_id()};
         getJdbcTemplate().update(modify);
     }
     @Override
     public void delete(int id) {
         String delete="delete from COST where COST_ID=?";
         Object[] params = {id};
         getJdbcTemplate().update(delete);
     }
 
}

注意:上面的程序在查找的时候需要传入一个RowMapper类型的参数,在这里我们需要重新定义一个类,继承自RowMapper类,然后重写mapRow()方法,主要作用是将从数据库中取出的数据对应的放入实体类对象中,我重写了Cost类对应的RowMapper类下:

package com.jeason.mappers;
 public class CostRowMapper implements RowMapper {
     @Override
     public Object mapRow(ResultSet rs, int index) throws SQLException {
         Cost cost = new Cost();
         try {
             cost.setCost_id(rs.getInt("cost_id"));
             cost.setName(rs.getString("name"));
             cost.setBase_duration(rs.getInt("base_duration"));
             cost.setBase_cost(rs.getDouble("base_cost"));
             cost.setUnit_cost(rs.getDouble("unit_cost"));
             cost.setDescr(rs.getString("descr"));
             cost.setStatus(rs.getString("status"));
             cost.setCost_type(rs.getString("cost_type"));
             cost.setCreatime(rs.getDate("creatime"));
             cost.setStartime(rs.getDate("startime"));
         } catch (SQLException e) {
             e.printStackTrace();
         }
         return cost;
     }
 }


5.最后将DAO组件交给Spring容器,进行相关配置,这是最后一步,也是最关键的一步,配置时主要有以下几步:        

      ---a.定义DAO组件的<bean>元素         

      ---b.需要给DAO的bean注入一个dataSource对象       

      ---c.dataSource对象采用一个连接池构建(我才用的是dbcp连接池),先引入dbcp连接池开发包,再定义dataSource对象<bean>

dbcp相关jar包下载

采用连接池有以下几个优点=====================        

               a.增强数据访问的稳定性         

               b.连接池可以将连接数控制在一定范围内        

               c.连接池中的对象使用完了之后会重新放回连接池内,避免了频繁的新建和释放连接操作,连接对象始终与数据库保持连通状态

如下,就是applicationContext.xml 文件中的配置:

<?xml version="1.0" encoding="UTF-8"?>
 <beans
     xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:p="http://www.springframework.org/schema/p"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
     <!-- 定义连接池组件 -->
     <bean id="MyDataSource"
             class="org.apache.commons.dbcp.BasicDataSource">
         <!-- 注入连接参数 -->
         <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
         <property name="driverClassName" value="oracle.jdbc.OracleDriver" />
         <property name="username" value="system" />
         <property name="password" value="zx123456" />
         <!-- 设置连接对象最大数 -->
         <property name="maxActive" value="20" />
         <property name="initialSize" value="2" />
     </bean>

     <bean id="costDao" class="com.jeason.dao.impl.JdbcCostDAO">
         <!-- 为DAO组件注入连接池对象 -->
         <property name="dataSource" ref="MyDataSource"/>
     </bean>
 </beans>

到此,就可以编写测试类来测试Spring+JDBC项目是否能正常运行,我的测试类如下:

package com.jeason.test;
 public class TestSpringJdbc {
     //测试查询
     @Test
     public void test1(){
         String cfg = "/applicationContext.xml";
         ApplicationContext ac = new ClassPathXmlApplicationContext(cfg);
         CostDAO cd = (CostDAO)ac.getBean("costDao");
         List<Cost> list = cd.findAll();
         for(Cost c: list){
             System.out.println(c.getCost_id()+"----->"+c.getName());
         }
     }
 }


以上是采用xml文件配置的方式利用Spring容器进行管理,我们也可以采用注解的方式将上面的JdbcCostDAO组件交给Spring容器管理,以下简单说一下采用注解方式的操作:

    首先在applicationContext.xml配置中开启组件扫描,加入以下配置:

        <context:component-scan base-package="com.jeason" />

    然后在JdbcCostDAO类中进行注解配置,在该类的声明前加上@Repository("jdbcCostDAO"),指明采用prototype方式实例化还可以加上 @Scope("prototype")

注意:由于这里要用到Spring提供的JdbcDaoSupport类,所以要将上面的连接池组件给该DAO组件注入,但是这里的DAO组件是继承自JdbcDAOSupport类,无法直接注入,可以在该类中定义一个方法,这里采用以下方法:

@Resource("dataSource")

public void setMyDataSource(DataSource ds){

        super.setDataSource(ds);

}



这个方法名自己定义,不过注意不要与父类JdbcDaoSupport中的方法名重名,然后在该set方法声明注解,将声明的dataSource组件注入。

然后就可以在applicationContext.xml配置中删除该DAO组件的配置了,但是别把连接池的配置也删了哦。这样就OK咯。