spring jdbcTemplate

Spring的JDBC框架能够承担资源管理和异常处理的工作,从而简化我们的JDBC代码,
让我们只需编写从数据库读写数据所必需的代码。Spring把数据访问的样板代码隐藏到模板类之下,
结合Spring的事务管理,可以大大简化我们的代码.

Spring提供了3个模板类:

JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。
NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数。
SimpleJdbcTemplate:利用Java 5的特性,比如自动装箱、通用(generic)和可变参数列表来简化JDBC模板的使用。
具体使用哪个模板基本上取决于个人喜好。


使用Spring的JdbcTemplate来实现简单的增删改查,首先建立测试数据表person
create table person(
id int not null primary key auto_increment,
name varchar(20) not null
)

导入依赖的jar包,由于测试中数据源使用的是dbcp数据源,需要以下jar包支持:
commons-logging.jar
commons-pool.jar
commons-dbcp.jar
同时还必须导入数据库驱动jar包:mysql-connector-java-3.1.8-bin.jar

建立实体bean
Person.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. public class PersonBean {  
   4.     private int id;  
   5.     private String name;  
   6.  
   7.     public PersonBean() {  
   8.     }  
   9.      
  10.     public PersonBean(String name) {  
  11.         this.name = name;  
  12.     }  
  13.      
  14.     public PersonBean(int id, String name) {  
  15.         this.id = id;  
  16.         this.name = name;  
  17.     }  
  18.        
  19.     public int getId() {  
  20.         return id;  
  21.     }  
  22.  
  23.     public void setId(int id) {  
  24.         this.id = id;  
  25.     }  
  26.  
  27.     public String getName() {  
  28.         return name;  
  29.     }  
  30.  
  31.     public void setName(String name) {  
  32.         this.name = name;  
  33.     }  
  34.      
  35.     public String toString() {  
  36.         return this.id + ":" + this.name;  
  37.     }  
  38. }  

package com.royzhou.jdbc;

public class PersonBean {
    private int id;
    private String name;

    public PersonBean() {
    }
    
    public PersonBean(String name) {
        this.name = name;
    }
    
    public PersonBean(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String toString() {
        return this.id + ":" + this.name;
    }
}



接口类:
PersonService.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. import java.util.List;  
   4.  
   5. public interface PersonService {  
   6.      
   7.     public void addPerson(PersonBean person);  
   8.      
   9.     public void updatePerson(PersonBean person);  
  10.      
  11.     public void deletePerson(int id);  
  12.      
  13.     public PersonBean queryPerson(int id);  
  14.      
  15.     public List<PersonBean> queryPersons();  
  16. }  

package com.royzhou.jdbc;

import java.util.List;

public interface PersonService {
    
    public void addPerson(PersonBean person);
    
    public void updatePerson(PersonBean person);
    
    public void deletePerson(int id);
    
    public PersonBean queryPerson(int id);
    
    public List<PersonBean> queryPersons();
}



实现类:
PersonServiceImpl.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. import java.util.List;  
   4.  
   5. import javax.sql.DataSource;  
   6. import java.sql.Types;  
   7.  
   8. import org.springframework.jdbc.core.JdbcTemplate;  
   9.  
  10. public class PersonServiceImpl implements PersonService {  
  11.  
  12.     private JdbcTemplate jdbcTemplate;  
  13.      
  14.     /**
  15.      * 通过Spring容器注入datasource
  16.      * 实例化JdbcTemplate,该类为主要操作数据库的类
  17.      * @param ds
  18.      */  
  19.     public void setDataSource(DataSource ds) {  
  20.         this.jdbcTemplate = new JdbcTemplate(ds);  
  21.     }  
  22.      
  23.     public void addPerson(PersonBean person) {  
  24.         /**
  25.          * 第一个参数为执行sql
  26.          * 第二个参数为参数数据
  27.          * 第三个参数为参数类型
  28.          */  
  29.         jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
  30.     }  
  31.  
  32.     public void deletePerson(int id) {  
  33.         jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
  34.     }  
  35.  
  36.     public PersonBean queryPerson(int id) {  
  37.         /**
  38.          * new PersonRowMapper()是一个实现RowMapper接口的类,
  39.          * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
  40.          */  
  41.         PersonBean pb = (PersonBean) jdbcTemplate.queryForObject("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
  42.         return pb;  
  43.     }  
  44.  
  45.     @SuppressWarnings("unchecked")  
  46.     public List<PersonBean> queryPersons() {  
  47.         List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
  48.         return pbs;  
  49.     }  
  50.  
  51.     public void updatePerson(PersonBean person) {  
  52.         jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
  53.     }  
  54. }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;

public class PersonServiceImpl implements PersonService {

    private JdbcTemplate jdbcTemplate;
    
    /**
     * 通过Spring容器注入datasource
     * 实例化JdbcTemplate,该类为主要操作数据库的类
     * @param ds
     */
    public void setDataSource(DataSource ds) {
        this.jdbcTemplate = new JdbcTemplate(ds);
    }
    
    public void addPerson(PersonBean person) {
        /**
         * 第一个参数为执行sql
         * 第二个参数为参数数据
         * 第三个参数为参数类型
         */
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
    }

    public void deletePerson(int id) {
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
    }

    public PersonBean queryPerson(int id) {
        /**
         * new PersonRowMapper()是一个实现RowMapper接口的类,
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
         */
        PersonBean pb = (PersonBean) jdbcTemplate.queryForObject("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
        return pb;
    }

    @SuppressWarnings("unchecked")
    public List<PersonBean> queryPersons() {
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
        return pbs;
    }

    public void updatePerson(PersonBean person) {
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
    }
}



PersonRowMapper.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. import java.sql.ResultSet;  
   4. import java.sql.SQLException;  
   5.  
   6. import org.springframework.jdbc.core.RowMapper;  
   7.  
   8. public class PersonRowMapper implements RowMapper {  
   9.     //默认已经执行rs.next(),可以直接取数据  
  10.     public Object mapRow(ResultSet rs, int index) throws SQLException {  
  11.         PersonBean pb = new PersonBean(rs.getInt("id"),rs.getString("name"));  
  12.         return pb;  
  13.     }  
  14. }  

package com.royzhou.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.jdbc.core.RowMapper;

public class PersonRowMapper implements RowMapper {
    //默认已经执行rs.next(),可以直接取数据
    public Object mapRow(ResultSet rs, int index) throws SQLException {
        PersonBean pb = new PersonBean(rs.getInt("id"),rs.getString("name"));
        return pb;
    }
}



我们需要在bean.xml中配置DataSource,并且将datasource注入到我们的业务类中

Xml代码

   1. <?xml version="1.0" encoding="UTF-8"?>  
   2. <beans xmlns="http://www.springframework.org/schema/beans"  
   3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   4.        xmlns:context="http://www.springframework.org/schema/context"  
   5.        xmlns:aop="http://www.springframework.org/schema/aop"  
   6.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
   7.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
   8.            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd   
   9.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">  
  10.  
  11.      <context:property-placeholder location="classpath:jdbc.properties"/>  
  12.      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  13.         <property name="driverClassName" value="${driverClassName}"/>  
  14.         <property name="url" value="${url}"/>  
  15.         <property name="username" value="${username}"/>  
  16.         <property name="password" value="${password}"/>  
  17.          <!-- 连接池启动时的初始值 -->  
  18.          <property name="initialSize" value="${initialSize}"/>  
  19.          <!-- 连接池的最大值 -->  
  20.          <property name="maxActive" value="${maxActive}"/>  
  21.          <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->  
  22.          <property name="maxIdle" value="${maxIdle}"/>  
  23.          <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->  
  24.          <property name="minIdle" value="${minIdle}"/>  
  25.      </bean>  
  26.      
  27. </beans>  

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">

     <context:property-placeholder location="classpath:jdbc.properties"/>
     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
         <!-- 连接池启动时的初始值 -->
         <property name="initialSize" value="${initialSize}"/>
         <!-- 连接池的最大值 -->
         <property name="maxActive" value="${maxActive}"/>
         <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
         <property name="maxIdle" value="${maxIdle}"/>
         <!--  最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
         <property name="minIdle" value="${minIdle}"/>
     </bean>
    
</beans>



jdbc.properties
Java代码

   1. driverClassName=org.gjt.mm.mysql.Driver  
   2. url=jdbc:mysql://localhost:3306/royzhou?useUnicode=true&characterEncoding=UTF-8  
   3. username=root  
   4. password=123456  
   5. initialSize=1  
   6. maxActive=500  
   7. maxIdle=2  
   8. minIdle=1  

driverClassName=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost:3306/royzhou?useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
initialSize=1
maxActive=500
maxIdle=2
minIdle=1



编写我们的测试类:TestJdbcTemplate.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. import org.springframework.context.ApplicationContext;  
   4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
   5.  
   6. public class TestJdbcTemplate {  
   7.     public static void main(String[] args) {  
   8.         ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");  
   9.         PersonService ps = (PersonService)ctx.getBean("personService");  
  10.         ps.addPerson(new PersonBean("royzhou"));  
  11.         PersonBean pb = ps.queryPerson(1);  
  12.         System.out.println(pb);  
  13.         pb.setName("haha");  
  14.         ps.updatePerson(pb);  
  15.         pb = ps.queryPerson(1);  
  16.         System.out.println(pb);  
  17.         ps.deletePerson(1);  
  18.         pb = ps.queryPerson(1);  
  19.         System.out.println(pb);  
  20.     }  
  21. }  

package com.royzhou.jdbc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbcTemplate {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
        PersonService ps = (PersonService)ctx.getBean("personService");
        ps.addPerson(new PersonBean("royzhou"));
        PersonBean pb = ps.queryPerson(1);
        System.out.println(pb);
        pb.setName("haha");
        ps.updatePerson(pb);
        pb = ps.queryPerson(1);
        System.out.println(pb);
        ps.deletePerson(1);
        pb = ps.queryPerson(1);
        System.out.println(pb);
    }
}



上面代码先插入一条记录,然后修改,之后删除,运行之后出现异常,异常信息:
EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

难道Spring的queryForObject在查找不到记录的时候会抛出异常,看了一下Spring的源代码 发现确实如此:
Java代码

   1. public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper) throws DataAccessException {  
   2.         List results = (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper, 1));  
   3.         return DataAccessUtils.requiredUniqueResult(results);  
   4.     }  
   5.  
   6.     public Object queryForObject(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {  
   7.         List results = (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper, 1));  
   8.         return DataAccessUtils.requiredUniqueResult(results);  
   9.     }  
  10.  
  11.     public Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {  
  12.         List results = query(sql, rowMapper);  
  13.         return DataAccessUtils.requiredUniqueResult(results);  
  14.     }  
  15.  
  16.     public static Object requiredUniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {  
  17.         int size = (results != null ? results.size() : 0);  
  18.         if (size == 0) {  
  19.             throw new EmptyResultDataAccessException(1); // 问题在这里  
  20.         }  
  21.         if (!CollectionUtils.hasUniqueObject(results)) {  
  22.             throw new IncorrectResultSizeDataAccessException(1, size);  
  23.         }  
  24.         return results.iterator().next();  
  25.     }  

public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper) throws DataAccessException {
        List results = (List) query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper, 1));
        return DataAccessUtils.requiredUniqueResult(results);
    }

    public Object queryForObject(String sql, Object[] args, RowMapper rowMapper) throws DataAccessException {
        List results = (List) query(sql, args, new RowMapperResultSetExtractor(rowMapper, 1));
        return DataAccessUtils.requiredUniqueResult(results);
    }

    public Object queryForObject(String sql, RowMapper rowMapper) throws DataAccessException {
        List results = query(sql, rowMapper);
        return DataAccessUtils.requiredUniqueResult(results);
    }

    public static Object requiredUniqueResult(Collection results) throws IncorrectResultSizeDataAccessException {
        int size = (results != null ? results.size() : 0);
        if (size == 0) {
            throw new EmptyResultDataAccessException(1); // 问题在这里
        }
        if (!CollectionUtils.hasUniqueObject(results)) {
            throw new IncorrectResultSizeDataAccessException(1, size);
        }
        return results.iterator().next();
    }



发现当查找不到记录是,requiredUniqueResult方法做了判断,抛出异常, 想不明白为什么Spring要在这里做这样的判断,为啥不返回null????

重新修改PersonServiceImple类,把queryPerson方法改为使用列表查询的方式再去根据index取
PersonServiceImpl.java
Java代码

   1. package com.royzhou.jdbc;  
   2.  
   3. import java.util.List;  
   4.  
   5. import javax.sql.DataSource;  
   6. import java.sql.Types;  
   7.  
   8. import org.springframework.jdbc.core.JdbcTemplate;  
   9.  
  10. public class PersonServiceImpl implements PersonService {  
  11.  
  12.     private JdbcTemplate jdbcTemplate;  
  13.      
  14.     /**
  15.      * 通过Spring容器注入datasource
  16.      * 实例化JdbcTemplate,该类为主要操作数据库的类
  17.      * @param ds
  18.      */  
  19.     public void setDataSource(DataSource ds) {  
  20.         this.jdbcTemplate = new JdbcTemplate(ds);  
  21.     }  
  22.      
  23.     public void addPerson(PersonBean person) {  
  24.         /**
  25.          * 第一个参数为执行sql
  26.          * 第二个参数为参数数据
  27.          * 第三个参数为参数类型
  28.          */  
  29.         jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});  
  30.     }  
  31.  
  32.     public void deletePerson(int id) {  
  33.         jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});  
  34.     }  
  35.  
  36.     @SuppressWarnings("unchecked")  
  37.     public PersonBean queryPerson(int id) {  
  38.         /**
  39.          * new PersonRowMapper()是一个实现RowMapper接口的类,
  40.          * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
  41.          */  
  42.         List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());  
  43.         PersonBean pb = null;  
  44.         if(pbs.size()>0) {  
  45.             pb = pbs.get(0);  
  46.         }  
  47.         return pb;  
  48.     }  
  49.  
  50.     @SuppressWarnings("unchecked")  
  51.     public List<PersonBean> queryPersons() {  
  52.         List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());  
  53.         return pbs;  
  54.     }  
  55.  
  56.     public void updatePerson(PersonBean person) {  
  57.         jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});  
  58.     }  
  59. }  

package com.royzhou.jdbc;

import java.util.List;

import javax.sql.DataSource;
import java.sql.Types;

import org.springframework.jdbc.core.JdbcTemplate;

public class PersonServiceImpl implements PersonService {

    private JdbcTemplate jdbcTemplate;
    
    /**
     * 通过Spring容器注入datasource
     * 实例化JdbcTemplate,该类为主要操作数据库的类
     * @param ds
     */
    public void setDataSource(DataSource ds) {
        this.jdbcTemplate = new JdbcTemplate(ds);
    }
    
    public void addPerson(PersonBean person) {
        /**
         * 第一个参数为执行sql
         * 第二个参数为参数数据
         * 第三个参数为参数类型
         */
        jdbcTemplate.update("insert into person values(null,?)", new Object[]{person.getName()}, new int[]{Types.VARCHAR});
    }

    public void deletePerson(int id) {
        jdbcTemplate.update("delete from person where id = ?", new Object[]{id}, new int[]{Types.INTEGER});
    }

    @SuppressWarnings("unchecked")
    public PersonBean queryPerson(int id) {
        /**
         * new PersonRowMapper()是一个实现RowMapper接口的类,
         * 执行回调,实现mapRow()方法将rs对象转换成PersonBean对象返回
         */
        List<PersonBean> pbs = (List<PersonBean>)jdbcTemplate.query("select id,name from person where id = ?", new Object[]{id}, new PersonRowMapper());
        PersonBean pb = null;
        if(pbs.size()>0) {
            pb = pbs.get(0);
        }
        return pb;
    }

    @SuppressWarnings("unchecked")
    public List<PersonBean> queryPersons() {
        List<PersonBean> pbs = (List<PersonBean>) jdbcTemplate.query("select id,name from person", new PersonRowMapper());
        return pbs;
    }

    public void updatePerson(PersonBean person) {
        jdbcTemplate.update("update person set name = ? where id = ?", new Object[]{person.getName(), person.getId()}, new int[]{Types.VARCHAR, Types.INTEGER});
    }
}



再次运行测试类,输出:
1:royzhou
1:haha
null

得到预期的结果.

你可能感兴趣的:(spring jdbcTemplate)