但行好事
莫论前程❤

Spring学习总结 —- JdbcTemplate详解

JdbcTemplate简介

  • Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
  • JdbcTemplate可以做的事情包括: 数据库连接[打开/关闭] ,异常转义 ,SQL执行 ,查询结果的转换
  • JdbcTemplate位于spring-jdbc-4.3.0RELEASE.jar中。其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate还需一个spring-tx-4.3.0.RELEASE.jar这个包包含了一下事务和异常控制.

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

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

下面进行案件分析

在src下面新建一个属性配置文件db.properties

1 jdbc.user=root
2 jdbc.password=123456
3 jdbc.driverClass=com.mysql.jdbc.Driver
4 jdbc.jdbcUrl=jdbc\:mysql\:///test

配置Spring配置文件applicationContext.xml

<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="user" value="${jdbc.user}"></property>
    <property name="password" value="${jdbc.password}"></property>
    <property name="driverClass" value="${jdbc.driverClass}"></property>
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

0、execute方法

1、update()方法

a、通过update插入数据

//启动IoC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//获取IoC容器中JdbcTemplate实例
JdbcTemplate jdbcTemplate=(JdbcTemplate) ctx.getBean("jdbcTemplate");
String sql="insert into user (name,deptid) values (?,?)";
int count= jdbcTemplate.update(sql, new Object[]{"caoyc",3});
System.out.println(count);

b、通过update修改数据

String sql="update user set name=?,deptid=? where id=?";
jdbcTemplate.update(sql,new Object[]{"zhh",5,51});


jdbcTemplate.update("INSERT INTO tblname VALUES(?,?,..)",                       
        new PreparedStatementSetter(){                            
               public void setValues(PreparedStatement ps) throws SQLException{        
                    ps.setLong(1, user.getId(1));   
                    ps.setString(2, user.getName(2));     
                    ps.setDate(3, new java.sql.Date(new Date().getTime());    
                    ps.setTimestamp(4, new Timestamp(new Date().getTime());  
               }                       
        }  
);  

c、通过update删除数据

String sql="delete from user where id=?";
jdbcTemplate.update(sql,51);

2、batchUpdate()批量插入、更新和删除方法

String sql="insert into user (name,deptid) values (?,?)";

List<Object[]> batchArgs=new ArrayList<Object[]>();
batchArgs.add(new Object[]{"caoyc",6});
batchArgs.add(new Object[]{"zhh",8});
batchArgs.add(new Object[]{"cjx",8});

jdbcTemplate.batchUpdate(sql, batchArgs);

3、从数据中读取数据到实体对象

package com.proc;

public class User {
    private Integer id;
    private String name;
    private Integer deptid;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getDeptid() {
        return deptid;
    }
    public void setDeptid(Integer deptid) {
        this.deptid = deptid;
    }

    public String toString() {
        return "User [id=" + id + ", name=" + name + ", deptid=" + deptid + "]";
    }
}

a、读取单个对象

  • query
jdbcTemplate.query("SELECT id,name,.. FROM tblname WHERE id=1",   
       new RowCallbackHandler(){   
              public void processRow(ResultSet rs) throws SQLException{   
                    user.setId(rs.getLong(1));   
                    user.setName(rs.getString(2));   
              }   
      }  
);    

// 返回值为list<User>
List uGroup = jdbcTemplate.query("SELECT id,name,.. FROM tblname WHERE igroup=1",   
     new RowMapper(){   
            public Object mapRow(ResultSet rs,int no) throws SQLException{   
                     User user = new User();   
                     user.setId(rs.getLong(1));   
                     user.setName(rs.getString(2));   
                     return user ;   
            }  
     }   
};   
  • queryForObject
String sql="select id,name,deptid from user where id=?";
RowMapper<User> rowMapper=new BeanPropertyRowMapper<User>(User.class);
User user= jdbcTemplate.queryForObject(sql, rowMapper,52);
System.out.println(user);
// 输出结果:
User [id=52, name=caoyc, deptid=6]

【注意】:

  • 1、使用BeanProperytRowMapper要求sql数据查询出来的列和实体属性需要一一对应。如果数据中列明和属性名不一致,在sql语句中需要用as重新取一个别名
  • 2、使用JdbcTemplate对象不能获取关联对象

b、读取多个对象

String sql="select id,name,deptid from user";

RowMapper<User> rowMapper=new BeanPropertyRowMapper<User>(User.class);
List<User> users= jdbcTemplate.query(sql, rowMapper);
for (User user : users) {
    System.out.println(user);
}
// 输出结果
...
User [id=49, name=姓名49, deptid=5]
User [id=50, name=姓名50, deptid=8]
User [id=52, name=caoyc, deptid=6]
User [id=53, name=zhh, deptid=8]
User [id=54, name=cjx, deptid=8]
---

c、获取某个记录某列或者count、avg、sum等函数返回唯一值

String sql="select count(*) from user";
int count= jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println(count);

jdbcTemplate.queryForXX()总结

jdbcTemplate.queryForInt()和jdbcTemplate.queryForLong()

使用queryForInt返回user表中的记录数量,queryForInt搭配这样的sql可以在分页的时候计算总记录数

int queryForInt(String sql) 

int queryForInt(String sql, Object[] args) //   args为需要传递的参数

例子:

int num = jdbcTemplate.queryForInt("select count(*) from user"); 

int uNum = jdbcTemplate.queryForInt("SELECT count(*) FROM tblname WHERE id>?",   
    new Integer []{5}); 

jdbcTemplate.queryForString()

String customerName = jdbcTemplate.queryForString("select username from customer where customerId=110"); 

jdbcTemplate.queryForObject()

本质上和queryForInt相同,只是可以返回不同的对象,例如返回一个String对象

Object queryForObject(String sql, Class requiredType) 

Object queryForObject(String sql, Object[] args, Class requiredType) 

例子:

String name = (String) jdbcTemplate.queryForObject(
"SELECT name FROM USER WHERE id = ?",                   # sql
new Object[] {id},                                     # 要传递的参数数组
java.lang.String.class);                               # 返回来的对象class 

jdbcTemplate.queryForMap(SQL)

这个查询只能是查询一条记录的查询,返回一个map,key的值是column的值

Map queryForMap(String sql) 

Map queryForMap(String sql, Object[] args) 

例子:

Map map = jdbcTemplate.queryForMap("select count(*) as keyval from user");
map.get("keyval")

jdbcTemplate.queryForRowSet()

返回一个RowSet   然后调用.getString或者getInt等去取值

jdbcTemplate.queryForList()

返回一个装有map的list,每一个map是一条记录,map里面的key是字段名

此处与hibernate不同 ,hibernate返回的对象可以直接绑定到java对象上.而jdbcTemplate不能.

queryForList方法根据传入的SQL以及相应的参数执行查询,将查询的结果以java.util.List的形式返回,返回的java.util.List中的每一个元素都是java.util.Map类型,分别对应结果集中的一行,Map的Key为每一列的列名,而Map的值就是当前行列名对应的值。

List queryForList(String sql) 

List queryForList(String sql, Object[] args) 

List queryForList(String sql, Object[] args, Class requiredType)     

例子:

List rows = jdbcTemplate.queryForList("SELECT * FROM user");        # 得到装有map的list
for(int i=0;i<rows.size();i++){                                     # 遍历
    Map userMap=rows.get(i);
    System.out.println(userMap.get("id"));  
    System.out.println(userMap.get("name"));  
    System.out.println(userMap.get("age"));
}
// ==================================================
List uNames = jdbcTemplate.queryForList("SELECT name FROM tblname WHERE id>?",   
    new Integer []{5}, String.class);   
//=======================================================================
List<Map> uMapList = (List<Map>) jdbcTemplate.queryForList( "SELECT id, name FROM tblname WHERE id>?", new Integer []{5});   
for(Map<String,Object> uMap :uMapList){   
      Integer id = uMap.get("id");   
      String name = uMap.get("name");   
}; 

好啦,如果这些还不足以满足你的查询需要,那么我们就更进一步,使用相应的Callback接口对查询结果的返回进行定制吧!

jdbcTemplate.query()

List customerList = (List)jdbcTemplate.query(sql, 回调接口);

用于查询的回调接口定义主要有以下三种:

org.springframework.jdbc.core.ResultSetExtractor.  基本上属于JdbcTemplate内部使用的Callback接口,相对于下面两个Callback接口来说,ResultSetExtractor拥有更多的控制权,因为使用它,你需要自行处理ResultSet: 

public interface ResultSetExtractor { 
    Object extractData(ResultSet rs) throws SQLException, DataAccessException; 
} 

在直接处理完ResultSet之后,你可以将处理后的结果以任何你想要的形式包装后返回。  org.springframework.jdbc.core.RowCallbackHandlerRowCallbackHandler相对于ResultSetExtractor来说,仅仅关注单行结果的处理,处理后的结果可以根据需要存放到当前RowCallbackHandler对象内或者使用JdbcTemplate的程序上下文中,当然,这个完全是看个人爱好了。 RowCallbackHandler的定义如下: 

public interface RowCallbackHandler { 
    void processRow(ResultSet rs) throws SQLException; 
} 

org.springframework.jdbc.core.RowMapperResultSetExtractor的精简版,功能类似于RowCallbackHandler,也只关注处理单行的结果,不过,处理后的结果会由ResultSetExtractor实现类进行组合。 RowMapper的接口定义如下: 

public interface RowMapper { 
    Object mapRow(ResultSet rs, int rowNum) throws SQLException; 
} 

为了说明这三种Callback接口的使用和相互之间的区别,我们暂且设定如下场景:  数据库表customer中存在多行信息,对该表查询后,我们需要将每一行的顾客信息都映射到域对象Customer中,并以java.util.List的形式返回所有的查询结果。  现在,我们分别使用这三种Callback接口对customer表进行查询:

  • ResultSetExtractor
List customerList = (List)jdbcTemplate.query("select * from customer", new ResultSetExtractor(){ 

    public Object extractData(ResultSet rs) throws SQLException,DataAccessException { 
        List customers = new ArrayList(); 
        while(rs.next()) { 
            Customer customer = new Customer(); 
            customer.setFirstName(rs.getString(1)); 
            customer.setLastName(rs.getString(2)); 
            ... 
            customers.add(customer); 
        } 
        return customers; 
    }
}); 
  • RowCallbackHandler
final List customerList = new ArrayList(); 
jdbcTemplate.query("select * from customer", new RowCallbackHandler(){ 

    public void processRow(ResultSet rs) throws SQLException { 
        Customer customer = new Customer(); 
        customer.setFirstName(rs.getString(1)); 
        customer.setLastName(rs.getString(2)); 
        ... 
        customerList.add(customer); 
    }
}); 
  • RowMapper
List customerList = jdbcTemplate.query("select * from customer", new RowMapper(){ 

    public Object mapRow(ResultSet rs, int rowNumber) throws SQLException { 
        Customer customer = new Customer(); 
        customer.setFirstName(rs.getString(1)); 
        customer.setLastName(rs.getString(2)); 
        ... 
        return customer; 
    }
}); 

使用三种Callback接口作为参数的query方法的返回值不同: 

  • ResultSetExtractor作为方法参数的query方法返回Object型结果,要使用查询结果,我们需要对其进行强制转型;
  • RowMapper接口作为方法参数的query方法直接返回List型的结果
  • RowCallbackHandler作为方法参数的query方法,返回值为void; 

    使用ResultSetExtractor作为Callback接口处理查询结果,我们需要自己声明集合类,自己遍历ResultSet,自己根据每行数据组装Customer对象,自己将组装后的Customer对象添加到集合类中,方法最终只负责将组装完成的集合返回;

使用RowMapper比直接使用ResultSetExtractor要方便的多,只负责处理单行结果就行,现在,我们只需要将单行的结果组装后返回就行,剩下的工作,全部都是JdbcTemplate内部的事情了。 实际上,JdbcTemplae内部会使用一个ResultSetExtractor实现类来做其余的工作,毕竟,该做的工作还得有人做不是?!

JdbcTemplae内部使用的这个ResultSetExtractor实现类为org.springframework.jdbc.core.RowMapperResultSetExtractor, 它内部持有一个RowMapper实例的引用,当处理结果集的时候,会将单行数据的处理委派给其所持有的RowMapper实例,而其余工作它负责:

public Object extractData(ResultSet rs) throws SQLException { 
    List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList()); 
    int rowNum = 0; 
    while (rs.next()) { 
        results.add(this.rowMapper.mapRow(rs, rowNum++)); 
    } 
    return results; 
} 

这下应该清楚为啥RowMapper为啥就处理单行结果就能完成ResultSetExtractor颇费周折的工作了吧?!  RowCallbackHandler虽然与RowMapper同是处理单行数据,不过,除了要处理单行结果,它还得负责最终结果的组装和获取工作,在这里我们是使用当前上下文声明的List取得最终查询结果, 不过,我们也可以单独声明一个RowCallbackHandler实现类,在其中声明相应的集合类,这样,我们可以通过该RowCallbackHandler实现类取得最终查询结果:

public class GenericRowCallbackHandler implements RowCallbackHandler { 
    private List collections = new ArrayList(); 

    public void processRow(ResultSet rs) throws SQLException { 
        Customer customer = new Customer(); 
        customer.setFirstName(rs.getString(1)); 
        customer.setLastName(rs.getString(2)); 
        ... 
        collections.add(customer); 
    } 

        public List getResults() { 
        return collections; 
    } 
} 

GenericRowCallbackHandler handler = new GenericRowCallbackHandler(); 
jdbcTemplate.query("select * from customer",handler()); 
List customerList = handler.getResults(); 

该使用方式是明了了,不过GenericRowCallbackHandler重用性不佳。 RowCallbackHandler因为也是处理单行数据,所以,总得有人来做遍历ResultSet的工作,这个人其实也是一个ResultSetExtractor实现类, 它是JdbcTemplate一个内部静态类,名为RowCallbackHandlerResultSetExtractor,一看它的定义你就知道奥秘之所在了: 

private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor { 

    private final RowCallbackHandler rch; 

    public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) { 
        this.rch = rch; 
    } 

    public Object extractData(ResultSet rs) throws SQLException { 
        while (rs.next()) { 
            this.rch.processRow(rs); 
        } 
        return null; 
    } 
} 

总的来说,内部工作归根结底是由ResultSetExtractor做了,RowCallbackHandler和RowMapper只是为了帮助我们简化使用上的操作而已。 所以,实际使用中,RowCallbackHandler和RowMapper才是我们最常用的选择。  对于使用JdbcTemplate进行查询,基本就这些内容了,当然,如果你非要使用基于StatementCallback之类更底层的execute方法的话,那就是你个人说了算啦。 不过,要想知道JdbcTemplate中有关查询相关模板方法的更多信息,在实际使用中参考JdbcTemplate的javadoc就可以,当然,有IDE就更便捷了。

RowMapper 自定义实例

public class UserDaoImpl {  
    private JdbcTemplate jdbcTemplate;  

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {  
        this.jdbcTemplate = jdbcTemplate;  
    }  

    public List<User> getUserByName(String username) {  
        String sql = "select * from t_user where username = ?";  
        Object[] params = new Object[] { username };  
        List<User> users = null;  
        /** 
         * 使用接口实现类 
         */  
        users = jdbcTemplate.query(sql, params, new UserRowMapper());  

        public class UserRowMapper implements RowMapper<User> {  

            @Override  
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {  
                User user = new User();  
                user.setId(rs.getInt("id"));  
                user.setUsername(rs.getString("username"));  
                user.setPassword(rs.getString("password"));  
                return user;  
            }    
        }  


        /** 
         * 使用匿名内部类 
         * 如果UserRowMapper类只使用一次,单独为其创建一个类多余,可以使用匿名类 
         * 省略了书写一个实现类 
         */  
        users = jdbcTemplate.query(sql, params,  
                new RowMapper<User>() {  
                    @Override  
                    public User mapRow(ResultSet rs, int rowNum) throws SQLException {  
                        User user = new User();  
                        user.setId(rs.getInt("id"));  
                        user.setUsername(rs.getString("username"));  
                        user.setPassword(rs.getString("password"));  
                        return user;  
                    }  
                });  
        return (users != null && users.size() > 0) ? users : null;  
    }  
} 
赞(1) 打赏
未经允许不得转载:刘鹏博客 » Spring学习总结 —- JdbcTemplate详解
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏