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.RowCallbackHandler
. RowCallbackHandler
相对于ResultSetExtractor
来说,仅仅关注单行结果的处理,处理后的结果可以根据需要存放到当前RowCallbackHandler
对象内或者使用JdbcTemplate的程序上下文中,当然,这个完全是看个人爱好了。 RowCallbackHandler
的定义如下:
public interface RowCallbackHandler {
void processRow(ResultSet rs) throws SQLException;
}
org.springframework.jdbc.core.RowMapper
. ResultSetExtractor
的精简版,功能类似于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;
}
}
评论前必须登录!
注册