spring jdbc包提供了JdbcTemplate和它的两个兄弟SimpleJdbcTemplate和NamedParameterJdbcTemplate,我们可以先从JdbcTemplate入手,领略一下这个类的便利和优雅。
1、使用JdbcTemplate进行数据访问:
初始化JdbcTemplate
初始化JdbcTemplate很容易,只需要向它的构造方法传入它所使用的DataSource便可以。如果使用Jakarta Commons DBCP,那么初始化代码如下所示:
1 BasicDataSource dataSource = new BasicDataSource();
2 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
3 dataSource.setUrl("jdbc:mysql://localhost/mysql?characterEncoding=gb2312");
4 dataSource.setUsername("***");
5 dataSource.setPassword("***");
6 JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
也可以通过无参的构造方法构造JdbcTemplate,然后通过setDataSource(DataSource dataSource)来设置其dataSource。
上述这种方法是通过编码的方式构造JdbcTemplate,如果应用程序使用spring的IOC容器,其初始化工作便可移植到容器的配置文件当中:
01 <!-- dataSource -->
02 <bean id="dataSource"
03 class="org.apache.commons.dbcp.BasicDataSource"
04 destroy-method="close">
05
06 <property name="driverClassName">
07 <value>com.mysql.jdbc.Driver</value>
08 </property>
09 <property name="url" value="jdbc:mysql://localhost:3306/oa?characterEncoding=gb2312" />
10 <property name="username" value="root" />
11 <property name="password" value="root" />
12 <property name="maxActive" value="100" />
13 <property name="maxIdle" value="30" />
14 <property name="maxWait" value="1000" />
15 <property name="defaultAutoCommit" value="true" />
16 <property name="removeAbandoned" value="true" />
17 </bean>
18 <!-- jdbcTemplate -->
19 <bean id="jdbc"
20 class="org.springframework.jdbc.core.JdbcTemplate">
21 <property name="dataSource">
22 <ref bean="dataSource" />
23 </property>
24 </bean>
之后,想把jdbcTemplate注入到哪个bean都可以,初始化好了JdbcTemplate以后,便可以大施拳脚了!
使用JdbcTemplate查询数据:
JdbcTemplate针对数据查询提供了多个重载的模板方法,我们可以根据需要选用不同的模板方法。如果查询很简单,仅仅是传入相应的SQL或者是相关的参数,然后取得一个结果,那么我们可以用如下的一组便利的模板方法:
1 public int queryForInt(String sql)
1 public int queryForInt(String sql, Object[] args)
1 public int queryForInt(String sql, Object[] args)
1 public long queryForLong(String sql)
1 public long queryForLong(String sql, Object[] args)
1 public long queryForLong(String sql, Object[] args, int[] argTypes)
1 public Object queryForObject(String sql, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, int[] argTypes, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper)
1 public Object queryForObject(String sql, Object[] args, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, RowMapper rowMapper)
1 public Object queryForObject(String sql, RowMapper rowMapper)
注意:这些针对的resultset返回的必须是一行记录,否则会出错!
如果查询的结果包含一列数字型的结果,或者使用了SQL函数,或者其它的单列的结果,那么便可以直接通过这组便利的模板方法进行查询:
1 int postId = jdbcTemplate.queryForInt("SELECT POSTID FROM USERS WHERE USERNAME=?",new String[]{"jason"});
2 System.out.println(postId);
3 long userCount = jdbcTemplate.queryForLong("SELECT COUNT(*) FROM USERS");
4 System.out.println(userCount);
5 String nickname = (String)jdbcTemplate.queryForObject("SELECT USERNAME1 FROM USERS WHERE USERNAME='jason'", String.class);
6 System.out.println(nickname);
7 Map singleUser = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME = 'jason'");
8 System.out.println(singleUser);
queryForMap与其它的方法的不同之处在于它的查询的结果以java.util.Map的形式返回,Map的键对应查询的表的列的名字,Map的值对应键所在的列的值。
如果查询的结果返回多行,而我们又不在乎他们是否拥有较强的约束类型,那么可以用以下的模板方法:
1 public List queryForList(String sql)
1 public List queryForList(String sql, Object[] args)
1 public List queryForList(String sql, Object[] args, int[] argTypes)
queryForList()方法根据传入的sql以及相应的参数执行查询,将查询的结果以java.util.List的形式返回,返回的java.util.List中的每个元素都是java.lang.Map类型,分别对应结果集中的一行,Map的键对应每列的列名,Map的值对应当前列名对应的值.
如果这些还不足以满足我们的需要,那么我们可以自己定义回调接口
用于查询的回调接口有以下三种:
org.springframework.jdbc.core.ResultSetExtractor,它是属于JdbcTemplate内部使用的Callback接口,相对于下面的两个接口,这个接口拥有更多的控制权,因为在使用它的时候,我们需要自行的处理ResultSet,该接口的定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 import org.springframework.dao.DataAccessException;
07
08 public interface ResultSetExtractor {
09
10
11 Object extractData(ResultSet rs) throws SQLException, DataAccessException;
12
13 }
我们可以将处理的结果以任意的形式包装后返回。
org.springframework.jdbc.core.RowCallbackHandler 相对于ResultSetExtractor,它只关注单行结果的处理,处理的结果可以根据需要存放在当前的RowCallbackHandler,或者使用JdbcTemplate中,当然,这完全看个人喜好,接口定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 public interface RowCallbackHandler {
07
08 void processRow(ResultSet rs) throws SQLException;
09
10 }<span style="font-family:''sans serif', tahoma, verdana, helvetica';font-size:x-small;"><span style="line-height:19px;white-space:normal;"> </span></span>
org.springframework.jdbc.core.RowMapper 它是 ResultSetExtractor的精简版,功能类似于 RowCallbackHandler,也是只关注当行结果的处理。不过它的返回的结果会有 ResultSetExtractor实现类进行组合。RowMapper的接口定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 public interface RowMapper {
07
08 Object mapRow(ResultSet rs, int rowNum) throws SQLException;
09
10 }
为了说明这三种回调接口的使用方法,我们暂时设置如下的场景: 假设我们有一表users,里面有userid,username,userpwd三个字段,我们为此建立了一个JavaBean:
01 package com.google.spring.jdbc;
02
03 public class UserBean
04 {
05 private Integer userId;
06 private String username;
07 private String userpwd;
08 public Integer getUserId()
09 {
10 return userId;
11 }
12 public void setUserId(Integer userId)
13 {
14 this.userId = userId;
15 }
16 public String getUsername()
17 {
18 return username;
19 }
20 public void setUsername(String username)
21 {
22 this.username = username;
23 }
24 public String getUserpwd()
25 {
26 return userpwd;
27 }
28 public void setUserpwd(String userpwd)
29 {
30 this.userpwd = userpwd;
31 }
32
33 }
使用自定义的ResultSetExtractor,可以如下进行处理:
01 List users = (List)jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new ResultSetExtractor()
02 {
03
04 @Override
05 public Object extractData(ResultSet rs) throws SQLException,
06 DataAccessException
07 {
08 List users = new ArrayList();
09 while(rs.next())
10 {
11 UserBean userBean = new UserBean();
12 userBean.setUserId(rs.getInt("userId"));
13 userBean.setUsername(rs.getString("username"));
14 userBean.setUserpwd(rs.getString("userpwd"));
15 users.add(userBean);
16 }
17 return users;
18 }
19 });
20 System.out.println(users);
使用RowMapper,可进行如下的处理:
01 List users = jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new RowMapper()
02 {
03
04 @Override
05 public Object mapRow(ResultSet rs, int rowNum) throws SQLException
06 {
07 UserBean userBean = new UserBean();
08 userBean.setUserId(rs.getInt("userId"));
09 userBean.setUsername(rs.getString("username"));
10 userBean.setUserpwd(rs.getString("userpwd"));
11 return userBean;
12 }
13 });
14 System.out.println(users.size());
使用RowCallbackHandler可进行如下的处理:
01 final List users = new ArrayList();
02 jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new RowCallbackHandler()
03 {
04
05 @Override
06 public void processRow(ResultSet rs) throws SQLException
07 {
08 UserBean userBean = new UserBean();
09 userBean.setUserId(rs.getInt("userId"));
10 userBean.setUsername(rs.getString("username"));
11 userBean.setUserpwd(rs.getString("userpwd"));
12 users.add(userBean);
13 }
14 });
15 System.out.println(users.size());
1、使用JdbcTemplate进行数据访问:
初始化JdbcTemplate
初始化JdbcTemplate很容易,只需要向它的构造方法传入它所使用的DataSource便可以。如果使用Jakarta Commons DBCP,那么初始化代码如下所示:
1 BasicDataSource dataSource = new BasicDataSource();
2 dataSource.setDriverClassName("com.mysql.jdbc.Driver");
3 dataSource.setUrl("jdbc:mysql://localhost/mysql?characterEncoding=gb2312");
4 dataSource.setUsername("***");
5 dataSource.setPassword("***");
6 JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
也可以通过无参的构造方法构造JdbcTemplate,然后通过setDataSource(DataSource dataSource)来设置其dataSource。
上述这种方法是通过编码的方式构造JdbcTemplate,如果应用程序使用spring的IOC容器,其初始化工作便可移植到容器的配置文件当中:
01 <!-- dataSource -->
02 <bean id="dataSource"
03 class="org.apache.commons.dbcp.BasicDataSource"
04 destroy-method="close">
05
06 <property name="driverClassName">
07 <value>com.mysql.jdbc.Driver</value>
08 </property>
09 <property name="url" value="jdbc:mysql://localhost:3306/oa?characterEncoding=gb2312" />
10 <property name="username" value="root" />
11 <property name="password" value="root" />
12 <property name="maxActive" value="100" />
13 <property name="maxIdle" value="30" />
14 <property name="maxWait" value="1000" />
15 <property name="defaultAutoCommit" value="true" />
16 <property name="removeAbandoned" value="true" />
17 </bean>
18 <!-- jdbcTemplate -->
19 <bean id="jdbc"
20 class="org.springframework.jdbc.core.JdbcTemplate">
21 <property name="dataSource">
22 <ref bean="dataSource" />
23 </property>
24 </bean>
之后,想把jdbcTemplate注入到哪个bean都可以,初始化好了JdbcTemplate以后,便可以大施拳脚了!
使用JdbcTemplate查询数据:
JdbcTemplate针对数据查询提供了多个重载的模板方法,我们可以根据需要选用不同的模板方法。如果查询很简单,仅仅是传入相应的SQL或者是相关的参数,然后取得一个结果,那么我们可以用如下的一组便利的模板方法:
1 public int queryForInt(String sql)
1 public int queryForInt(String sql, Object[] args)
1 public int queryForInt(String sql, Object[] args)
1 public long queryForLong(String sql)
1 public long queryForLong(String sql, Object[] args)
1 public long queryForLong(String sql, Object[] args, int[] argTypes)
1 public Object queryForObject(String sql, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, int[] argTypes, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, int[] argTypes, RowMapper rowMapper)
1 public Object queryForObject(String sql, Object[] args, Class requiredType)
1 public Object queryForObject(String sql, Object[] args, RowMapper rowMapper)
1 public Object queryForObject(String sql, RowMapper rowMapper)
注意:这些针对的resultset返回的必须是一行记录,否则会出错!
如果查询的结果包含一列数字型的结果,或者使用了SQL函数,或者其它的单列的结果,那么便可以直接通过这组便利的模板方法进行查询:
1 int postId = jdbcTemplate.queryForInt("SELECT POSTID FROM USERS WHERE USERNAME=?",new String[]{"jason"});
2 System.out.println(postId);
3 long userCount = jdbcTemplate.queryForLong("SELECT COUNT(*) FROM USERS");
4 System.out.println(userCount);
5 String nickname = (String)jdbcTemplate.queryForObject("SELECT USERNAME1 FROM USERS WHERE USERNAME='jason'", String.class);
6 System.out.println(nickname);
7 Map singleUser = jdbcTemplate.queryForMap("SELECT * FROM USERS WHERE USERNAME = 'jason'");
8 System.out.println(singleUser);
queryForMap与其它的方法的不同之处在于它的查询的结果以java.util.Map的形式返回,Map的键对应查询的表的列的名字,Map的值对应键所在的列的值。
如果查询的结果返回多行,而我们又不在乎他们是否拥有较强的约束类型,那么可以用以下的模板方法:
1 public List queryForList(String sql)
1 public List queryForList(String sql, Object[] args)
1 public List queryForList(String sql, Object[] args, int[] argTypes)
queryForList()方法根据传入的sql以及相应的参数执行查询,将查询的结果以java.util.List的形式返回,返回的java.util.List中的每个元素都是java.lang.Map类型,分别对应结果集中的一行,Map的键对应每列的列名,Map的值对应当前列名对应的值.
如果这些还不足以满足我们的需要,那么我们可以自己定义回调接口
用于查询的回调接口有以下三种:
org.springframework.jdbc.core.ResultSetExtractor,它是属于JdbcTemplate内部使用的Callback接口,相对于下面的两个接口,这个接口拥有更多的控制权,因为在使用它的时候,我们需要自行的处理ResultSet,该接口的定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 import org.springframework.dao.DataAccessException;
07
08 public interface ResultSetExtractor {
09
10
11 Object extractData(ResultSet rs) throws SQLException, DataAccessException;
12
13 }
我们可以将处理的结果以任意的形式包装后返回。
org.springframework.jdbc.core.RowCallbackHandler 相对于ResultSetExtractor,它只关注单行结果的处理,处理的结果可以根据需要存放在当前的RowCallbackHandler,或者使用JdbcTemplate中,当然,这完全看个人喜好,接口定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 public interface RowCallbackHandler {
07
08 void processRow(ResultSet rs) throws SQLException;
09
10 }<span style="font-family:''sans serif', tahoma, verdana, helvetica';font-size:x-small;"><span style="line-height:19px;white-space:normal;"> </span></span>
org.springframework.jdbc.core.RowMapper 它是 ResultSetExtractor的精简版,功能类似于 RowCallbackHandler,也是只关注当行结果的处理。不过它的返回的结果会有 ResultSetExtractor实现类进行组合。RowMapper的接口定义如下:
01 package org.springframework.jdbc.core;
02
03 import java.sql.ResultSet;
04 import java.sql.SQLException;
05
06 public interface RowMapper {
07
08 Object mapRow(ResultSet rs, int rowNum) throws SQLException;
09
10 }
为了说明这三种回调接口的使用方法,我们暂时设置如下的场景: 假设我们有一表users,里面有userid,username,userpwd三个字段,我们为此建立了一个JavaBean:
01 package com.google.spring.jdbc;
02
03 public class UserBean
04 {
05 private Integer userId;
06 private String username;
07 private String userpwd;
08 public Integer getUserId()
09 {
10 return userId;
11 }
12 public void setUserId(Integer userId)
13 {
14 this.userId = userId;
15 }
16 public String getUsername()
17 {
18 return username;
19 }
20 public void setUsername(String username)
21 {
22 this.username = username;
23 }
24 public String getUserpwd()
25 {
26 return userpwd;
27 }
28 public void setUserpwd(String userpwd)
29 {
30 this.userpwd = userpwd;
31 }
32
33 }
使用自定义的ResultSetExtractor,可以如下进行处理:
01 List users = (List)jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new ResultSetExtractor()
02 {
03
04 @Override
05 public Object extractData(ResultSet rs) throws SQLException,
06 DataAccessException
07 {
08 List users = new ArrayList();
09 while(rs.next())
10 {
11 UserBean userBean = new UserBean();
12 userBean.setUserId(rs.getInt("userId"));
13 userBean.setUsername(rs.getString("username"));
14 userBean.setUserpwd(rs.getString("userpwd"));
15 users.add(userBean);
16 }
17 return users;
18 }
19 });
20 System.out.println(users);
使用RowMapper,可进行如下的处理:
01 List users = jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new RowMapper()
02 {
03
04 @Override
05 public Object mapRow(ResultSet rs, int rowNum) throws SQLException
06 {
07 UserBean userBean = new UserBean();
08 userBean.setUserId(rs.getInt("userId"));
09 userBean.setUsername(rs.getString("username"));
10 userBean.setUserpwd(rs.getString("userpwd"));
11 return userBean;
12 }
13 });
14 System.out.println(users.size());
使用RowCallbackHandler可进行如下的处理:
01 final List users = new ArrayList();
02 jdbcTemplate.query("SELECT * FROM USERS WHERE USERNAME LIKE '%n%'", new RowCallbackHandler()
03 {
04
05 @Override
06 public void processRow(ResultSet rs) throws SQLException
07 {
08 UserBean userBean = new UserBean();
09 userBean.setUserId(rs.getInt("userId"));
10 userBean.setUsername(rs.getString("username"));
11 userBean.setUserpwd(rs.getString("userpwd"));
12 users.add(userBean);
13 }
14 });
15 System.out.println(users.size());